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:
authorGitLab Bot <gitlab-bot@gitlab.com>2023-09-21 06:10:15 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2023-09-21 06:10:15 +0300
commitd63d9aebd74436a74f1ff45e26f6565341d5956b (patch)
treee4b4606da3edb0dd7b7f9d11a119f956890c5e81
parent11bda5e7e1637e5b0ace597aafbd45f12b429c32 (diff)
Add latest changes from gitlab-org/gitlab@master
-rw-r--r--Gemfile2
-rw-r--r--Gemfile.checksum20
-rw-r--r--Gemfile.lock4
-rw-r--r--app/assets/javascripts/ci/common/pipelines_table.vue64
-rw-r--r--app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js11
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue19
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue58
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue31
-rw-r--r--app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue3
-rw-r--r--app/assets/javascripts/ci/pipelines_page/pipelines.vue9
-rw-r--r--app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue11
-rw-r--r--app/assets/javascripts/commit/pipelines/pipelines_bundle.js2
-rw-r--r--app/assets/javascripts/merge_request_tabs.js14
-rw-r--r--app/helpers/merge_requests_helper.rb4
-rw-r--r--app/models/analytics/cycle_analytics/issue_stage_event.rb40
-rw-r--r--app/models/analytics/cycle_analytics/merge_request_stage_event.rb4
-rw-r--r--app/models/concerns/analytics/cycle_analytics/stage_event_model.rb77
-rw-r--r--app/views/admin/application_settings/_sentry.html.haml25
-rw-r--r--db/migrate/20230918123357_add_sprint_id_and_weight_to_vsa_issues.rb15
-rw-r--r--db/schema_migrations/202309181233571
-rw-r--r--db/structure.sql132
-rw-r--r--locale/gitlab.pot26
-rw-r--r--spec/db/schema_spec.rb2
-rw-r--r--spec/frontend/ci/common/pipelines_table_spec.js162
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js69
-rw-r--r--spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js42
-rw-r--r--spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js97
27 files changed, 635 insertions, 309 deletions
diff --git a/Gemfile b/Gemfile
index 54e82d50fc8..5516307a5bf 100644
--- a/Gemfile
+++ b/Gemfile
@@ -253,7 +253,7 @@ gem 'rainbow', '~> 3.0'
gem 'ruby-progressbar', '~> 1.10'
# Linear-time regex library for untrusted regular expressions
-gem 're2', '2.0.0'
+gem 're2', '2.1.2'
# Misc
diff --git a/Gemfile.checksum b/Gemfile.checksum
index e1ee62e12ec..702f6471230 100644
--- a/Gemfile.checksum
+++ b/Gemfile.checksum
@@ -491,16 +491,16 @@
{"name":"rbtree","version":"0.4.6","platform":"ruby","checksum":"14eea4469b24fd2472542e5f3eb105d6344c8ccf36f0b56d55fdcfeb4e0f10fc"},
{"name":"rchardet","version":"1.8.0","platform":"ruby","checksum":"693acd5253d5ade81a51940697955f6dd4bb2f0d245bda76a8e23deec70a52c7"},
{"name":"rdoc","version":"6.3.2","platform":"ruby","checksum":"def4a720235c27d56c176ae73555e647eb04ea58a8bbaa927f8f9f79de7805a6"},
-{"name":"re2","version":"2.0.0","platform":"aarch64-linux","checksum":"677ddce4c38d659de899651acbfd7c6b5331f984a7101d9179ac247284f2212a"},
-{"name":"re2","version":"2.0.0","platform":"arm-linux","checksum":"f657d689922e5ac215b486e4f2ca909f1079eab616269a1d8fc0cccd63ef28af"},
-{"name":"re2","version":"2.0.0","platform":"arm64-darwin","checksum":"ffc8e5663381ff344ee6a2e55c7d0be81ef9b43174a41e977c4e18a11f965be1"},
-{"name":"re2","version":"2.0.0","platform":"ruby","checksum":"09075fab88b7ab40c2374d75a20504408dc26539c11931b146d5f72892718925"},
-{"name":"re2","version":"2.0.0","platform":"x64-mingw-ucrt","checksum":"253b3de21ca563cdb93c9fd69738a2a66713e381bae4530ff2cae105c6fd1a8e"},
-{"name":"re2","version":"2.0.0","platform":"x64-mingw32","checksum":"d4b52fc21719f262c2a438912f009da868b31aed1688ec90e4e1696898fb53d3"},
-{"name":"re2","version":"2.0.0","platform":"x86-linux","checksum":"26abee219e3fd69ba5c6a7bdb882880b8af6502cf912da7a7837e38ad02a29e7"},
-{"name":"re2","version":"2.0.0","platform":"x86-mingw32","checksum":"ffec6da4c547e44a6c1a467b0b01b2dcc2940e081923221a2ac3e4b08a219c26"},
-{"name":"re2","version":"2.0.0","platform":"x86_64-darwin","checksum":"48b3ba3fea8cc84709a4195300cd1c627b2496f16e5865662c54e67f7aca1ccf"},
-{"name":"re2","version":"2.0.0","platform":"x86_64-linux","checksum":"1fb161e6e5d9efed59ed0062536f2cb9ab5fba367e209d0dc66f99f2864d42ff"},
+{"name":"re2","version":"2.1.2","platform":"aarch64-linux","checksum":"dbd87fb2432f17734cfb948d38cb0d138335228d31c4316719c75ac0a976731f"},
+{"name":"re2","version":"2.1.2","platform":"arm-linux","checksum":"4c0d903508bc0d82f27d09c84498e0fdc6ab87ef418bea884d711b85f7fca62f"},
+{"name":"re2","version":"2.1.2","platform":"arm64-darwin","checksum":"39bb8a44a4afbd2d3f2e07d531d223728f7c4b83946bc55e8ce6aae8c2c34579"},
+{"name":"re2","version":"2.1.2","platform":"ruby","checksum":"06bd25bf566dda720cbc607ceecb65ed16871427fbcb3e5239c300ec796fee9c"},
+{"name":"re2","version":"2.1.2","platform":"x64-mingw-ucrt","checksum":"a1ad9cda576dae6020664c7578d7e43d2062ca21e5e945aea125f539944ee713"},
+{"name":"re2","version":"2.1.2","platform":"x64-mingw32","checksum":"804fc9bafc6590e3e75d27d289546d7223b51bf3e46e9d81ee89cf5168c1a9be"},
+{"name":"re2","version":"2.1.2","platform":"x86-linux","checksum":"6a048f8a1511a5481f7a386045e67ecbb221a856d2987b33a231efb5e17250bc"},
+{"name":"re2","version":"2.1.2","platform":"x86-mingw32","checksum":"8e0e9d0f3166ff3000ffa38a05c9e5275ba431f2abce494fa7600033206ce108"},
+{"name":"re2","version":"2.1.2","platform":"x86_64-darwin","checksum":"6b41f328b551173e58eb04320c70295de143b5aeb38c78122aa623a4308bc472"},
+{"name":"re2","version":"2.1.2","platform":"x86_64-linux","checksum":"e082a1db722b7da3adc9e1f9d8681cba80a2d1176c54ae741443965ce277e6af"},
{"name":"recaptcha","version":"5.12.3","platform":"ruby","checksum":"37d1894add9e70a54d0c6c7f0ecbeedffbfa7d075acfbd4c509818dfdebdb7ee"},
{"name":"recursive-open-struct","version":"1.1.3","platform":"ruby","checksum":"a3538a72552fcebcd0ada657bdff313641a4a5fbc482c08cfb9a65acb1c9de5a"},
{"name":"redcarpet","version":"3.6.0","platform":"ruby","checksum":"8ad1889c0355ff4c47174af14edd06d62f45a326da1da6e8a121d59bdcd2e9e9"},
diff --git a/Gemfile.lock b/Gemfile.lock
index 7285dff310c..8b812860e84 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -1296,7 +1296,7 @@ GEM
rbtree (0.4.6)
rchardet (1.8.0)
rdoc (6.3.2)
- re2 (2.0.0)
+ re2 (2.1.2)
mini_portile2 (~> 2.8.4)
recaptcha (5.12.3)
json
@@ -1963,7 +1963,7 @@ DEPENDENCIES
rainbow (~> 3.0)
rbtrace (~> 0.4)
rdoc (~> 6.3.2)
- re2 (= 2.0.0)
+ re2 (= 2.1.2)
recaptcha (~> 5.12)
redis (~> 4.8.0)
redis-actionpack (~> 5.3.0)
diff --git a/app/assets/javascripts/ci/common/pipelines_table.vue b/app/assets/javascripts/ci/common/pipelines_table.vue
index 807128d2341..0c73c0c412f 100644
--- a/app/assets/javascripts/ci/common/pipelines_table.vue
+++ b/app/assets/javascripts/ci/common/pipelines_table.vue
@@ -8,9 +8,7 @@ import { TRACKING_CATEGORIES } from '~/ci/constants';
import { keepLatestDownstreamPipelines } from '~/ci/pipeline_details/utils/parsing_utils';
import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
import PipelineFailedJobsWidget from '~/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue';
-import eventHub from '~/ci/event_hub';
import PipelineOperations from '../pipelines_page/components/pipeline_operations.vue';
-import PipelineStopModal from '../pipelines_page/components/pipeline_stop_modal.vue';
import PipelineTriggerer from '../pipelines_page/components/pipeline_triggerer.vue';
import PipelineUrl from '../pipelines_page/components/pipeline_url.vue';
import PipelinesStatusBadge from '../pipelines_page/components/pipelines_status_badge.vue';
@@ -19,6 +17,23 @@ const HIDE_TD_ON_MOBILE = 'gl-display-none! gl-lg-display-table-cell!';
const DEFAULT_TH_CLASSES =
'gl-bg-transparent! gl-border-b-solid! gl-border-b-gray-100! gl-p-5! gl-border-b-1!';
+/**
+ * Pipelines Table
+ *
+ * Presentational component of a table of pipelines. This component does not
+ * fetch the list of pipelines and instead expects it as a prop.
+ * GraphQL actions for pipelines, such as retrying, canceling, etc.
+ * are handled within this component.
+ *
+ * Use this `legacy_pipelines_table_wrapper` if you need a fully functional REST component.
+ *
+ * IMPORTANT: When using this component, make sure to handle the following events:
+ * 1- @refresh-pipeline-table
+ * 2- @cancel-pipeline
+ * 3- @retry-pipeline
+ *
+ */
+
export default {
components: {
GlTableLite,
@@ -26,7 +41,6 @@ export default {
PipelineFailedJobsWidget,
PipelineOperations,
PipelinesStatusBadge,
- PipelineStopModal,
PipelineTriggerer,
PipelineUrl,
},
@@ -63,14 +77,6 @@ export default {
required: true,
},
},
- data() {
- return {
- pipelineId: 0,
- pipeline: {},
- endpoint: '',
- cancelingPipeline: null,
- };
- },
computed: {
showFailedJobsWidget() {
return this.glFeatures.ciJobFailuresInMr;
@@ -131,17 +137,6 @@ export default {
return this.pipelines;
},
},
- watch: {
- pipelines() {
- this.cancelingPipeline = null;
- },
- },
- created() {
- eventHub.$on('openConfirmationModal', this.setModalData);
- },
- beforeDestroy() {
- eventHub.$off('openConfirmationModal', this.setModalData);
- },
methods: {
getDownstreamPipelines(pipeline) {
const downstream = pipeline.triggered;
@@ -153,14 +148,16 @@ export default {
failedJobsCount(pipeline) {
return pipeline?.failed_builds?.length || 0;
},
- setModalData(data) {
- this.pipelineId = data.pipeline.id;
- this.pipeline = data.pipeline;
- this.endpoint = data.endpoint;
+ onRefreshPipelinesTable() {
+ this.$emit('refresh-pipelines-table');
+ },
+ onRetryPipeline(pipeline) {
+ // This emit is only used by the `legacy_pipelines_table_wrapper`.
+ this.$emit('retry-pipeline', pipeline);
},
- onSubmit() {
- eventHub.$emit('postAction', this.endpoint);
- this.cancelingPipeline = this.pipelineId;
+ onCancelPipeline(pipeline) {
+ // This emit is only used by the `legacy_pipelines_table_wrapper`.
+ this.$emit('cancel-pipeline', pipeline);
},
trackPipelineMiniGraph() {
this.track('click_minigraph', { label: TRACKING_CATEGORIES.table });
@@ -219,7 +216,12 @@ export default {
</template>
<template #cell(actions)="{ item }">
- <pipeline-operations :pipeline="item" :canceling-pipeline="cancelingPipeline" />
+ <pipeline-operations
+ :pipeline="item"
+ @cancel-pipeline="onCancelPipeline"
+ @refresh-pipelines-table="onRefreshPipelinesTable"
+ @retry-pipeline="onRetryPipeline"
+ />
</template>
<template #row-details="{ item }">
@@ -234,7 +236,5 @@ export default {
/>
</template>
</gl-table-lite>
-
- <pipeline-stop-modal :pipeline="pipeline" @submit="onSubmit" />
</div>
</template>
diff --git a/app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js b/app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js
index 53f755fda37..5d1f1ac770c 100644
--- a/app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js
+++ b/app/assets/javascripts/ci/pipeline_details/mixins/pipelines_mixin.js
@@ -52,14 +52,12 @@ export default {
});
eventHub.$on('postAction', this.postAction);
- eventHub.$on('retryPipeline', this.postAction);
eventHub.$on('clickedDropdown', this.updateTable);
eventHub.$on('updateTable', this.updateTable);
eventHub.$on('runMergeRequestPipeline', this.runMergeRequestPipeline);
},
beforeDestroy() {
eventHub.$off('postAction', this.postAction);
- eventHub.$off('retryPipeline', this.postAction);
eventHub.$off('clickedDropdown', this.updateTable);
eventHub.$off('updateTable', this.updateTable);
eventHub.$off('runMergeRequestPipeline', this.runMergeRequestPipeline);
@@ -68,6 +66,15 @@ export default {
this.poll.stop();
},
methods: {
+ onCancelPipeline(pipeline) {
+ this.postAction(pipeline.cancel_path);
+ },
+ onRefreshPipelinesTable() {
+ this.updateTable();
+ },
+ onRetryPipeline(pipeline) {
+ this.postAction(pipeline.retry_path);
+ },
updateInternalState(parameters) {
this.poll.stop();
diff --git a/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue b/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue
index 235126fea0c..ddcc566af13 100644
--- a/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/nav_controls.vue
@@ -7,28 +7,25 @@ export default {
GlButton,
},
props: {
- newPipelinePath: {
+ ciLintPath: {
type: String,
required: false,
default: null,
},
-
- resetCachePath: {
- type: String,
+ isResetCacheButtonLoading: {
+ type: Boolean,
required: false,
- default: null,
+ default: false,
},
-
- ciLintPath: {
+ newPipelinePath: {
type: String,
required: false,
default: null,
},
-
- isResetCacheButtonLoading: {
- type: Boolean,
+ resetCachePath: {
+ type: String,
required: false,
- default: false,
+ default: null,
},
},
methods: {
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue
index b05bdae65c4..746d605d852 100644
--- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_operations.vue
@@ -1,22 +1,22 @@
<script>
-import { GlButton, GlTooltipDirective, GlModalDirective } from '@gitlab/ui';
+import { GlButton, GlTooltipDirective } from '@gitlab/ui';
import Tracking from '~/tracking';
import { BUTTON_TOOLTIP_RETRY, BUTTON_TOOLTIP_CANCEL, TRACKING_CATEGORIES } from '~/ci/constants';
-import eventHub from '../../event_hub';
import PipelineMultiActions from './pipeline_multi_actions.vue';
import PipelinesManualActions from './pipelines_manual_actions.vue';
+import PipelineStopModal from './pipeline_stop_modal.vue';
export default {
BUTTON_TOOLTIP_RETRY,
BUTTON_TOOLTIP_CANCEL,
directives: {
GlTooltip: GlTooltipDirective,
- GlModalDirective,
},
components: {
GlButton,
PipelineMultiActions,
PipelinesManualActions,
+ PipelineStopModal,
},
mixins: [Tracking.mixin()],
props: {
@@ -24,15 +24,12 @@ export default {
type: Object,
required: true,
},
- cancelingPipeline: {
- type: Number,
- required: false,
- default: null,
- },
},
data() {
return {
+ isCanceling: false,
isRetrying: false,
+ showConfirmationModal: false,
};
},
computed: {
@@ -41,27 +38,36 @@ export default {
this.pipeline?.details?.has_manual_actions || this.pipeline?.details?.has_scheduled_actions
);
},
- isCancelling() {
- return this.cancelingPipeline === this.pipeline.id;
- },
},
watch: {
pipeline() {
- this.isRetrying = false;
+ if (this.isCanceling || this.isRetrying) {
+ this.isCanceling = false;
+ this.isRetrying = false;
+ }
},
},
methods: {
+ onCloseModal() {
+ this.showConfirmationModal = false;
+ },
+ onConfirmCancelPipeline() {
+ this.isCanceling = true;
+ this.showConfirmationModal = false;
+
+ this.$emit('cancel-pipeline', this.pipeline);
+ },
handleCancelClick() {
+ this.showConfirmationModal = true;
+
this.trackClick('click_cancel_button');
- eventHub.$emit('openConfirmationModal', {
- pipeline: this.pipeline,
- endpoint: this.pipeline.cancel_path,
- });
},
handleRetryClick() {
this.isRetrying = true;
+
this.trackClick('click_retry_button');
- eventHub.$emit('retryPipeline', this.pipeline.retry_path);
+
+ this.$emit('retry-pipeline', this.pipeline);
},
trackClick(action) {
this.track(action, { label: TRACKING_CATEGORIES.table });
@@ -72,8 +78,19 @@ export default {
<template>
<div class="gl-text-right">
+ <pipeline-stop-modal
+ :pipeline="pipeline"
+ :show-confirmation-modal="showConfirmationModal"
+ @submit="onConfirmCancelPipeline"
+ @close-modal="onCloseModal"
+ />
+
<div class="btn-group">
- <pipelines-manual-actions v-if="hasActions" :iid="pipeline.iid" />
+ <pipelines-manual-actions
+ v-if="hasActions"
+ :iid="pipeline.iid"
+ @refresh-pipeline-table="$emit('refresh-pipelines-table')"
+ />
<gl-button
v-if="pipeline.flags.retryable"
@@ -94,11 +111,10 @@ export default {
<gl-button
v-if="pipeline.flags.cancelable"
v-gl-tooltip.hover
- v-gl-modal-directive="'confirmation-modal'"
:aria-label="$options.BUTTON_TOOLTIP_CANCEL"
:title="$options.BUTTON_TOOLTIP_CANCEL"
- :loading="isCancelling"
- :disabled="isCancelling"
+ :loading="isCanceling"
+ :disabled="isCanceling"
icon="cancel"
variant="danger"
category="primary"
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue b/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue
index 9f38be668f2..d62a68f0dcc 100644
--- a/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipeline_stop_modal.vue
@@ -7,7 +7,7 @@ import CiIcon from '~/vue_shared/components/ci_icon.vue';
/**
* Pipeline Stop Modal.
*
- * Renders the modal used to confirm stopping a pipeline.
+ * Renders the modal used to confirm cancelling a pipeline.
*/
export default {
components: {
@@ -22,8 +22,15 @@ export default {
required: true,
deep: true,
},
+ showConfirmationModal: {
+ type: Boolean,
+ required: true,
+ },
},
computed: {
+ hasRef() {
+ return !isEmpty(this.pipeline.ref);
+ },
modalTitle() {
return sprintf(
s__('Pipeline|Stop pipeline #%{pipelineId}?'),
@@ -34,10 +41,7 @@ export default {
);
},
modalText() {
- return s__(`Pipeline|You’re about to stop pipeline #%{pipelineId}.`);
- },
- hasRef() {
- return !isEmpty(this.pipeline.ref);
+ return s__(`Pipeline|You're about to stop pipeline #%{pipelineId}.`);
},
primaryProps() {
return {
@@ -45,10 +49,13 @@ export default {
attributes: { variant: 'danger' },
};
},
- cancelProps() {
- return {
- text: __('Cancel'),
- };
+ showModal: {
+ get() {
+ return this.showConfirmationModal;
+ },
+ set() {
+ this.$emit('close-modal');
+ },
},
},
methods: {
@@ -56,14 +63,16 @@ export default {
this.$emit('submit', event);
},
},
+ cancelProps: { text: __('Cancel') },
};
</script>
<template>
<gl-modal
+ v-model="showModal"
modal-id="confirmation-modal"
:title="modalTitle"
:action-primary="primaryProps"
- :action-cancel="cancelProps"
+ :action-cancel="$options.cancelProps"
@primary="emitSubmit($event)"
>
<p>
@@ -74,7 +83,7 @@ export default {
</gl-sprintf>
</p>
- <p v-if="pipeline">
+ <p>
<ci-icon
v-if="pipeline.details"
:status="pipeline.details.status"
diff --git a/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue b/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue
index 4dacd474bde..ebf1744aee2 100644
--- a/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue
+++ b/app/assets/javascripts/ci/pipelines_page/components/pipelines_manual_actions.vue
@@ -6,7 +6,6 @@ import { confirmAction } from '~/lib/utils/confirm_via_gl_modal/confirm_via_gl_m
import { s__, __, sprintf } from '~/locale';
import Tracking from '~/tracking';
import GlCountdown from '~/vue_shared/components/gl_countdown.vue';
-import eventHub from '../../event_hub';
import { TRACKING_CATEGORIES } from '../../constants';
import getPipelineActionsQuery from '../graphql/queries/get_pipeline_actions.query.graphql';
@@ -94,7 +93,7 @@ export default {
.post(`${action.playPath}.json`)
.then(() => {
this.isLoading = false;
- eventHub.$emit('updateTable');
+ this.$emit('refresh-pipeline-table');
})
.catch(() => {
this.isLoading = false;
diff --git a/app/assets/javascripts/ci/pipelines_page/pipelines.vue b/app/assets/javascripts/ci/pipelines_page/pipelines.vue
index 87ee5463bb0..f4105040f31 100644
--- a/app/assets/javascripts/ci/pipelines_page/pipelines.vue
+++ b/app/assets/javascripts/ci/pipelines_page/pipelines.vue
@@ -13,7 +13,7 @@ import {
RAW_TEXT_WARNING,
TRACKING_CATEGORIES,
} from '~/ci/constants';
-import PipelinesTableComponent from '~/ci/common/pipelines_table.vue';
+import PipelinesTable from '~/ci/common/pipelines_table.vue';
import PipelinesMixin from '~/ci/pipeline_details/mixins/pipelines_mixin';
import { validateParams } from '~/ci/pipeline_details/utils';
import NavigationTabs from '~/vue_shared/components/navigation_tabs.vue';
@@ -37,7 +37,7 @@ export default {
NavigationTabs,
NavigationControls,
PipelinesFilteredSearch,
- PipelinesTableComponent,
+ PipelinesTable,
TablePagination,
},
mixins: [PipelinesMixin, Tracking.mixin()],
@@ -431,12 +431,15 @@ export default {
/>
<div v-else-if="stateToRender === $options.stateMap.tableList">
- <pipelines-table-component
+ <pipelines-table
:pipelines="state.pipelines"
:pipeline-schedule-url="pipelineScheduleUrl"
:update-graph-dropdown="updateGraphDropdown"
:view-type="viewType"
:pipeline-key-option="selectedPipelineKeyOption"
+ @cancel-pipeline="onCancelPipeline"
+ @refresh-pipelines-table="onRefreshPipelinesTable"
+ @retry-pipeline="onRetryPipeline"
/>
</div>
diff --git a/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue
index 5e84dcbe48e..5586032233c 100644
--- a/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue
+++ b/app/assets/javascripts/commit/pipelines/legacy_pipelines_table_wrapper.vue
@@ -2,7 +2,7 @@
import { GlButton, GlEmptyState, GlLoadingIcon, GlModal, GlLink, GlSprintf } from '@gitlab/ui';
import { helpPagePath } from '~/helpers/help_page_helper';
import { getParameterByName } from '~/lib/utils/url_utility';
-import PipelinesTableComponent from '~/ci/common/pipelines_table.vue';
+import PipelinesTable from '~/ci/common/pipelines_table.vue';
import { PipelineKeyOptions } from '~/ci/constants';
import eventHub from '~/ci/event_hub';
import PipelinesMixin from '~/ci/pipeline_details/mixins/pipelines_mixin';
@@ -21,7 +21,7 @@ export default {
GlLoadingIcon,
GlModal,
GlSprintf,
- PipelinesTableComponent,
+ PipelinesTable,
TablePagination,
},
mixins: [PipelinesMixin, glFeatureFlagMixin()],
@@ -279,11 +279,14 @@ export default {
{{ $options.i18n.runPipelineText }}
</gl-button>
- <pipelines-table-component
+ <pipelines-table
:pipelines="state.pipelines"
:update-graph-dropdown="updateGraphDropdown"
:view-type="viewType"
:pipeline-key-option="$options.PipelineKeyOptions[0]"
+ @cancel-pipeline="onCancelPipeline"
+ @refresh-pipelines-table="onRefreshPipelinesTable"
+ @retry-pipeline="onRetryPipeline"
>
<template #table-header-actions>
<div v-if="canRenderPipelineButton" class="gl-text-right">
@@ -296,7 +299,7 @@ export default {
</gl-button>
</div>
</template>
- </pipelines-table-component>
+ </pipelines-table>
</div>
<gl-modal
diff --git a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
index beeb9b9ada4..6ca59f634a2 100644
--- a/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
+++ b/app/assets/javascripts/commit/pipelines/pipelines_bundle.js
@@ -11,7 +11,7 @@ const apolloProvider = new VueApollo({
/**
* Used in:
- * - Project Pipelines List (projects:pipelines:index)
+ * - Project Pipelines List (projects:pipelines)
* - Commit details View > Pipelines Tab > Pipelines Table (projects:commit:pipelines)
* - Merge request details View > Pipelines Tab > Pipelines Table (projects:merge_requests:show)
* - New merge request View > Pipelines Tab > Pipelines Table (projects:merge_requests:creations:new)
diff --git a/app/assets/javascripts/merge_request_tabs.js b/app/assets/javascripts/merge_request_tabs.js
index 1bc67522e82..03518d5fdd1 100644
--- a/app/assets/javascripts/merge_request_tabs.js
+++ b/app/assets/javascripts/merge_request_tabs.js
@@ -93,7 +93,7 @@ function mountPipelines() {
const { mrWidgetData } = gl;
const table = new Vue({
components: {
- CommitPipelinesTable: () => {
+ MergeRequestPipelinesTable: () => {
return gon.features.mrPipelinesGraphql
? import('~/ci/merge_requests/components/pipelines_table_wrapper.vue')
: import('~/commit/pipelines/legacy_pipelines_table_wrapper.vue');
@@ -112,7 +112,7 @@ function mountPipelines() {
withFailedJobsDetails: true,
},
render(createElement) {
- return createElement('commit-pipelines-table', {
+ return createElement('merge-request-pipelines-table', {
props: {
endpoint: pipelineTableViewEl.dataset.endpoint,
emptyStateSvgPath: pipelineTableViewEl.dataset.emptyStateSvgPath,
@@ -347,11 +347,11 @@ export default class MergeRequestTabs {
}
// this.hideSidebar();
this.resetViewContainer();
- this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable);
+ this.mergeRequestPipelinesTable = destroyPipelines(this.mergeRequestPipelinesTable);
} else if (action === 'new') {
this.expandView();
this.resetViewContainer();
- this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable);
+ this.mergeRequestPipelinesTable = destroyPipelines(this.mergeRequestPipelinesTable);
} else if (this.isDiffAction(action)) {
if (!isInVueNoteablePage()) {
/*
@@ -366,7 +366,7 @@ export default class MergeRequestTabs {
}
// this.hideSidebar();
this.expandViewContainer();
- this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable);
+ this.mergeRequestPipelinesTable = destroyPipelines(this.mergeRequestPipelinesTable);
this.commitsTab.classList.remove('active');
} else if (action === 'pipelines') {
// this.hideSidebar();
@@ -384,7 +384,7 @@ export default class MergeRequestTabs {
// this.showSidebar();
this.resetViewContainer();
- this.commitPipelinesTable = destroyPipelines(this.commitPipelinesTable);
+ this.mergeRequestPipelinesTable = destroyPipelines(this.mergeRequestPipelinesTable);
}
renderGFM(document.querySelector('.detail-page-description'));
@@ -522,7 +522,7 @@ export default class MergeRequestTabs {
}
mountPipelinesView() {
- this.commitPipelinesTable = mountPipelines();
+ this.mergeRequestPipelinesTable = mountPipelines();
}
// load the diff tab content from the backend
diff --git a/app/helpers/merge_requests_helper.rb b/app/helpers/merge_requests_helper.rb
index a90a16e120c..bdb2744be71 100644
--- a/app/helpers/merge_requests_helper.rb
+++ b/app/helpers/merge_requests_helper.rb
@@ -78,10 +78,6 @@ module MergeRequestsHelper
.execute(include_routes: true)
end
- def merge_request_button_visibility(merge_request, closed)
- return 'hidden' if merge_request_button_hidden?(merge_request, closed)
- end
-
def merge_request_button_hidden?(merge_request, closed)
merge_request.closed? == closed || (merge_request.merged? == closed && !merge_request.closed?) || merge_request.closed_or_merged_without_fork?
end
diff --git a/app/models/analytics/cycle_analytics/issue_stage_event.rb b/app/models/analytics/cycle_analytics/issue_stage_event.rb
index 837eb35c839..4930788c8b5 100644
--- a/app/models/analytics/cycle_analytics/issue_stage_event.rb
+++ b/app/models/analytics/cycle_analytics/issue_stage_event.rb
@@ -17,12 +17,42 @@ module Analytics
where(condition.arel.exists)
end
- def self.issuable_id_column
- :issue_id
- end
+ class << self
+ def project_column
+ :project_id
+ end
+
+ def issuable_id_column
+ :issue_id
+ end
+
+ def issuable_model
+ ::Issue
+ end
+
+ def select_columns
+ [
+ *super,
+ issuable_model.arel_table[:weight],
+ issuable_model.arel_table[:sprint_id]
+ ]
+ end
+
+ def column_list
+ [
+ *super,
+ :weight,
+ :sprint_id
+ ]
+ end
- def self.issuable_model
- ::Issue
+ def insert_column_list
+ [
+ *super,
+ :weight,
+ :sprint_id
+ ]
+ end
end
end
end
diff --git a/app/models/analytics/cycle_analytics/merge_request_stage_event.rb b/app/models/analytics/cycle_analytics/merge_request_stage_event.rb
index 0dfa322b2c3..7f85d284034 100644
--- a/app/models/analytics/cycle_analytics/merge_request_stage_event.rb
+++ b/app/models/analytics/cycle_analytics/merge_request_stage_event.rb
@@ -17,6 +17,10 @@ module Analytics
where(condition.arel.exists)
end
+ def self.project_column
+ :target_project_id
+ end
+
def self.issuable_id_column
:merge_request_id
end
diff --git a/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb b/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb
index d268c32c088..8f20e3880b3 100644
--- a/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb
+++ b/app/models/concerns/analytics/cycle_analytics/stage_event_model.rb
@@ -57,45 +57,19 @@ module Analytics
class_methods do
def upsert_data(data)
- upsert_values = data.map do |row|
- row.values_at(
- :stage_event_hash_id,
- :issuable_id,
- :group_id,
- :project_id,
- :milestone_id,
- :author_id,
- :state_id,
- :start_event_timestamp,
- :end_event_timestamp
- )
- end
+ upsert_values = data.map { |row| row.values_at(*column_list) }
value_list = Arel::Nodes::ValuesList.new(upsert_values).to_sql
query = <<~SQL
INSERT INTO #{quoted_table_name}
(
- stage_event_hash_id,
- #{connection.quote_column_name(issuable_id_column)},
- group_id,
- project_id,
- milestone_id,
- author_id,
- state_id,
- start_event_timestamp,
- end_event_timestamp
+ #{insert_column_list.join(",\n")}
)
#{value_list}
ON CONFLICT(stage_event_hash_id, #{issuable_id_column})
DO UPDATE SET
- group_id = excluded.group_id,
- project_id = excluded.project_id,
- milestone_id = excluded.milestone_id,
- author_id = excluded.author_id,
- state_id = excluded.state_id,
- start_event_timestamp = excluded.start_event_timestamp,
- end_event_timestamp = excluded.end_event_timestamp
+ #{column_updates.join(",\n")}
SQL
result = connection.execute(query)
@@ -113,6 +87,51 @@ module Analytics
def arel_order(arel_node, direction)
direction.to_sym == :desc ? arel_node.desc : arel_node.asc
end
+
+ def select_columns
+ [
+ issuable_model.arel_table[:id],
+ issuable_model.arel_table[project_column].as('project_id'),
+ issuable_model.arel_table[:milestone_id],
+ issuable_model.arel_table[:author_id],
+ issuable_model.arel_table[:state_id],
+ Project.arel_table[:parent_id].as('group_id')
+ ]
+ end
+
+ def column_list
+ [
+ :stage_event_hash_id,
+ :issuable_id,
+ :group_id,
+ :project_id,
+ :milestone_id,
+ :author_id,
+ :state_id,
+ :start_event_timestamp,
+ :end_event_timestamp
+ ]
+ end
+
+ def insert_column_list
+ [
+ :stage_event_hash_id,
+ connection.quote_column_name(issuable_id_column),
+ :group_id,
+ :project_id,
+ :milestone_id,
+ :author_id,
+ :state_id,
+ :start_event_timestamp,
+ :end_event_timestamp
+ ]
+ end
+
+ def column_updates
+ insert_column_list.map do |column|
+ "#{column} = excluded.#{column}"
+ end
+ end
end
end
end
diff --git a/app/views/admin/application_settings/_sentry.html.haml b/app/views/admin/application_settings/_sentry.html.haml
index 9f2a40e4e54..7058a4b5cca 100644
--- a/app/views/admin/application_settings/_sentry.html.haml
+++ b/app/views/admin/application_settings/_sentry.html.haml
@@ -1,28 +1,31 @@
= gitlab_ui_form_for @application_setting, url: metrics_and_profiling_admin_application_settings_path(anchor: 'js-sentry-settings'), html: { class: 'fieldset-form', id: 'sentry-settings' } do |f|
= form_errors(@application_setting)
- %span.text-muted
- = _('Changing any setting here requires an application restart')
+ %fieldset.gl-text-secondary
+ = safe_format(s_('AdminSettings|GitLab uses the %{bold_start}Rails%{bold_end} and %{bold_start}Browser JavaScript%{bold_end} Sentry SDKs to send events to Sentry. For changes to Rails integration settings to take effect, restart GitLab.'), tag_pair(tag.b, :bold_start, :bold_end))
%fieldset
.form-group
- = f.gitlab_ui_checkbox_component :sentry_enabled, _('Enable Sentry error tracking')
+ = f.gitlab_ui_checkbox_component :sentry_enabled, s_('AdminSettings|Enable Sentry for Rails and Browser JavaScript')
+ .form-group
+ = f.label :sentry_environment, _('Environment'), class: 'label-light'
+ = f.text_field :sentry_environment, class: 'form-control gl-form-input', placeholder: Rails.env
+ .form-text.text-muted
+ = safe_format(s_('AdminSettings|%{setting_name} value used by both Rails and Browser JavaScript SDKs.'), setting_name: content_tag(:code, 'environment'))
.form-group
= f.label :sentry_dsn, _('DSN'), class: 'label-light'
= f.text_field :sentry_dsn, class: 'form-control gl-form-input', placeholder: 'https://public@sentry.example.com/1'
+ .form-text.text-muted
+ = safe_format(s_('AdminSettings|%{setting_name} value used by the Rails SDK.'), setting_name: content_tag(:code, 'dsn'))
.form-group
= f.label :sentry_clientside_dsn, _('Clientside DSN'), class: 'label-light'
= f.text_field :sentry_clientside_dsn, class: 'form-control gl-form-input', placeholder: 'https://public@sentry.example.com/2'
- .form-group
- = f.label :sentry_environment, _('Environment'), class: 'label-light'
- = f.text_field :sentry_environment, class: 'form-control gl-form-input', placeholder: Rails.env
-
- %p.text-muted
- = _("Changing any setting bellow doesn't require an application restart")
-
- %fieldset
+ .form-text.text-muted
+ = safe_format(s_('AdminSettings|%{setting_name} value used by the Browser JavaScript SDK.'), setting_name: content_tag(:code, 'dsn'))
.form-group
= f.label :sentry_clientside_traces_sample_rate, _('Clientside traces sample rate'), class: 'label-light'
= f.number_field :sentry_clientside_traces_sample_rate, class: 'form-control gl-form-input', placeholder: '0.5', min: 0, max: 1, step: 0.001
+ .form-text.text-muted
+ = safe_format(s_('AdminSettings|%{setting_name} value used by the Browser JavaScript SDK.'), setting_name: content_tag(:code, 'tracesSampleRate'))
= f.submit _('Save changes'), pajamas_button: true
diff --git a/db/migrate/20230918123357_add_sprint_id_and_weight_to_vsa_issues.rb b/db/migrate/20230918123357_add_sprint_id_and_weight_to_vsa_issues.rb
new file mode 100644
index 00000000000..0c3b7b3086a
--- /dev/null
+++ b/db/migrate/20230918123357_add_sprint_id_and_weight_to_vsa_issues.rb
@@ -0,0 +1,15 @@
+# frozen_string_literal: true
+
+class AddSprintIdAndWeightToVsaIssues < Gitlab::Database::Migration[2.1]
+ enable_lock_retries!
+
+ def up
+ add_column :analytics_cycle_analytics_issue_stage_events, :weight, :integer
+ add_column :analytics_cycle_analytics_issue_stage_events, :sprint_id, :bigint
+ end
+
+ def down
+ remove_column :analytics_cycle_analytics_issue_stage_events, :sprint_id
+ remove_column :analytics_cycle_analytics_issue_stage_events, :weight
+ end
+end
diff --git a/db/schema_migrations/20230918123357 b/db/schema_migrations/20230918123357
new file mode 100644
index 00000000000..5fc1d62a963
--- /dev/null
+++ b/db/schema_migrations/20230918123357
@@ -0,0 +1 @@
+99e55170557dcda361f441d1333f4dc9d99133a469f1d17805478f3407d2a093 \ No newline at end of file
diff --git a/db/structure.sql b/db/structure.sql
index bd055a1ba70..e4f04117e69 100644
--- a/db/structure.sql
+++ b/db/structure.sql
@@ -720,7 +720,9 @@ CREATE TABLE analytics_cycle_analytics_issue_stage_events (
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
)
PARTITION BY HASH (stage_event_hash_id);
@@ -733,7 +735,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_00 FOR VALUES WITH (modulus 32, remainder 0);
@@ -746,7 +750,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_01 FOR VALUES WITH (modulus 32, remainder 1);
@@ -759,7 +765,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_02 FOR VALUES WITH (modulus 32, remainder 2);
@@ -772,7 +780,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_03 FOR VALUES WITH (modulus 32, remainder 3);
@@ -785,7 +795,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_04 FOR VALUES WITH (modulus 32, remainder 4);
@@ -798,7 +810,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_05 FOR VALUES WITH (modulus 32, remainder 5);
@@ -811,7 +825,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_06 FOR VALUES WITH (modulus 32, remainder 6);
@@ -824,7 +840,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_07 FOR VALUES WITH (modulus 32, remainder 7);
@@ -837,7 +855,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_08 FOR VALUES WITH (modulus 32, remainder 8);
@@ -850,7 +870,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_09 FOR VALUES WITH (modulus 32, remainder 9);
@@ -863,7 +885,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_10 FOR VALUES WITH (modulus 32, remainder 10);
@@ -876,7 +900,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_11 FOR VALUES WITH (modulus 32, remainder 11);
@@ -889,7 +915,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_12 FOR VALUES WITH (modulus 32, remainder 12);
@@ -902,7 +930,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_13 FOR VALUES WITH (modulus 32, remainder 13);
@@ -915,7 +945,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_14 FOR VALUES WITH (modulus 32, remainder 14);
@@ -928,7 +960,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_15 FOR VALUES WITH (modulus 32, remainder 15);
@@ -941,7 +975,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_16 FOR VALUES WITH (modulus 32, remainder 16);
@@ -954,7 +990,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_17 FOR VALUES WITH (modulus 32, remainder 17);
@@ -967,7 +1005,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_18 FOR VALUES WITH (modulus 32, remainder 18);
@@ -980,7 +1020,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_19 FOR VALUES WITH (modulus 32, remainder 19);
@@ -993,7 +1035,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_20 FOR VALUES WITH (modulus 32, remainder 20);
@@ -1006,7 +1050,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_21 FOR VALUES WITH (modulus 32, remainder 21);
@@ -1019,7 +1065,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_22 FOR VALUES WITH (modulus 32, remainder 22);
@@ -1032,7 +1080,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_23 FOR VALUES WITH (modulus 32, remainder 23);
@@ -1045,7 +1095,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_24 FOR VALUES WITH (modulus 32, remainder 24);
@@ -1058,7 +1110,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_25 FOR VALUES WITH (modulus 32, remainder 25);
@@ -1071,7 +1125,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_26 FOR VALUES WITH (modulus 32, remainder 26);
@@ -1084,7 +1140,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_27 FOR VALUES WITH (modulus 32, remainder 27);
@@ -1097,7 +1155,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_28 FOR VALUES WITH (modulus 32, remainder 28);
@@ -1110,7 +1170,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_29 FOR VALUES WITH (modulus 32, remainder 29);
@@ -1123,7 +1185,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_30 FOR VALUES WITH (modulus 32, remainder 30);
@@ -1136,7 +1200,9 @@ CREATE TABLE gitlab_partitions_static.analytics_cycle_analytics_issue_stage_even
author_id bigint,
start_event_timestamp timestamp with time zone NOT NULL,
end_event_timestamp timestamp with time zone,
- state_id smallint DEFAULT 1 NOT NULL
+ state_id smallint DEFAULT 1 NOT NULL,
+ weight integer,
+ sprint_id bigint
);
ALTER TABLE ONLY analytics_cycle_analytics_issue_stage_events ATTACH PARTITION gitlab_partitions_static.analytics_cycle_analytics_issue_stage_events_31 FOR VALUES WITH (modulus 32, remainder 31);
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 2bf98cdc780..5d568647f4d 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -3375,6 +3375,15 @@ msgstr ""
msgid "AdminProjects|Delete Project %{projectName}?"
msgstr ""
+msgid "AdminSettings|%{setting_name} value used by both Rails and Browser JavaScript SDKs."
+msgstr ""
+
+msgid "AdminSettings|%{setting_name} value used by the Browser JavaScript SDK."
+msgstr ""
+
+msgid "AdminSettings|%{setting_name} value used by the Rails SDK."
+msgstr ""
+
msgid "AdminSettings|%{strongStart}WARNING:%{strongEnd} Environment variable %{environment_variable} does not exist or is not pointing to a valid directory. %{icon_link}"
msgstr ""
@@ -3450,6 +3459,9 @@ msgstr ""
msgid "AdminSettings|Enable Registration Features"
msgstr ""
+msgid "AdminSettings|Enable Sentry for Rails and Browser JavaScript"
+msgstr ""
+
msgid "AdminSettings|Enable Service Ping"
msgstr ""
@@ -3492,6 +3504,9 @@ msgstr ""
msgid "AdminSettings|Git abuse rate limit"
msgstr ""
+msgid "AdminSettings|GitLab uses the %{bold_start}Rails%{bold_end} and %{bold_start}Browser JavaScript%{bold_end} Sentry SDKs to send events to Sentry. For changes to Rails integration settings to take effect, restart GitLab."
+msgstr ""
+
msgid "AdminSettings|Group runners expiration"
msgstr ""
@@ -9610,12 +9625,6 @@ msgstr ""
msgid "Changes:"
msgstr ""
-msgid "Changing any setting bellow doesn't require an application restart"
-msgstr ""
-
-msgid "Changing any setting here requires an application restart"
-msgstr ""
-
msgid "Characters left"
msgstr ""
@@ -17959,9 +17968,6 @@ msgstr ""
msgid "Enable SSL verification"
msgstr ""
-msgid "Enable Sentry error tracking"
-msgstr ""
-
msgid "Enable Snowplow tracking"
msgstr ""
@@ -34963,7 +34969,7 @@ msgstr ""
msgid "Pipeline|We are currently unable to fetch pipeline data"
msgstr ""
-msgid "Pipeline|You’re about to stop pipeline #%{pipelineId}."
+msgid "Pipeline|You're about to stop pipeline #%{pipelineId}."
msgstr ""
msgid "Pipeline|for"
diff --git a/spec/db/schema_spec.rb b/spec/db/schema_spec.rb
index cfd6bbf3094..e4e1772f08e 100644
--- a/spec/db/schema_spec.rb
+++ b/spec/db/schema_spec.rb
@@ -36,7 +36,7 @@ RSpec.describe 'Database schema', feature_category: :database do
approvers: %w[target_id user_id],
analytics_cycle_analytics_aggregations: %w[last_full_issues_id last_full_merge_requests_id last_incremental_issues_id last_full_run_issues_id last_full_run_merge_requests_id last_incremental_merge_requests_id last_consistency_check_issues_stage_event_hash_id last_consistency_check_issues_issuable_id last_consistency_check_merge_requests_stage_event_hash_id last_consistency_check_merge_requests_issuable_id],
analytics_cycle_analytics_merge_request_stage_events: %w[author_id group_id merge_request_id milestone_id project_id stage_event_hash_id state_id],
- analytics_cycle_analytics_issue_stage_events: %w[author_id group_id issue_id milestone_id project_id stage_event_hash_id state_id],
+ analytics_cycle_analytics_issue_stage_events: %w[author_id group_id issue_id milestone_id project_id stage_event_hash_id state_id sprint_id],
audit_events: %w[author_id entity_id target_id],
award_emoji: %w[awardable_id user_id],
aws_roles: %w[role_external_id],
diff --git a/spec/frontend/ci/common/pipelines_table_spec.js b/spec/frontend/ci/common/pipelines_table_spec.js
index 26dd1a2fcc5..1ddeb901e59 100644
--- a/spec/frontend/ci/common/pipelines_table_spec.js
+++ b/spec/frontend/ci/common/pipelines_table_spec.js
@@ -1,9 +1,7 @@
-import '~/commons';
import { GlTableLite } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
import fixture from 'test_fixtures/pipelines/pipelines.json';
import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
import LegacyPipelineMiniGraph from '~/ci/pipeline_mini_graph/legacy_pipeline_mini_graph.vue';
import PipelineFailedJobsWidget from '~/ci/pipelines_page/components/failure_widget/pipeline_failed_jobs_widget.vue';
import PipelineOperations from '~/ci/pipelines_page/components/pipeline_operations.vue';
@@ -20,14 +18,12 @@ import {
import CiBadgeLink from '~/vue_shared/components/ci_badge_link.vue';
-jest.mock('~/ci/event_hub');
-
describe('Pipelines Table', () => {
- let pipeline;
let wrapper;
let trackingSpy;
const defaultProvide = {
+ fullPath: '/my-project/',
glFeatures: {},
withFailedJobsDetails: false,
};
@@ -39,32 +35,31 @@ describe('Pipelines Table', () => {
withFailedJobsDetails: true,
};
+ const { pipelines } = fixture;
+
const defaultProps = {
- pipelines: [],
+ pipelines,
viewType: 'root',
pipelineKeyOption: PipelineKeyOptions[0],
};
- const createMockPipeline = () => {
- // Clone fixture as it could be modified by tests
- const { pipelines } = JSON.parse(JSON.stringify(fixture));
- return pipelines.find((p) => p.user !== null && p.commit !== null);
- };
-
- const createComponent = (props = {}, provide = {}) => {
- wrapper = extendedWrapper(
- mount(PipelinesTable, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- provide: {
- ...defaultProvide,
- ...provide,
- },
- stubs: ['PipelineFailedJobsWidget'],
- }),
- );
+ const [firstPipeline] = pipelines;
+
+ const createComponent = ({ props = {}, provide = {}, stubs = {} } = {}) => {
+ wrapper = mountExtended(PipelinesTable, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ provide: {
+ ...defaultProvide,
+ ...provide,
+ },
+ stubs: {
+ PipelineOperations: true,
+ ...stubs,
+ },
+ });
};
const findGlTableLite = () => wrapper.findComponent(GlTableLite);
@@ -84,13 +79,9 @@ describe('Pipelines Table', () => {
const findRetryBtn = () => wrapper.findByTestId('pipelines-retry-button');
const findCancelBtn = () => wrapper.findByTestId('pipelines-cancel-button');
- beforeEach(() => {
- pipeline = createMockPipeline();
- });
-
describe('Pipelines Table', () => {
beforeEach(() => {
- createComponent({ pipelines: [pipeline], viewType: 'root' });
+ createComponent({ props: { viewType: 'root' } });
});
it('displays table', () => {
@@ -105,7 +96,7 @@ describe('Pipelines Table', () => {
});
it('should display a table row', () => {
- expect(findTableRows()).toHaveLength(1);
+ expect(findTableRows()).toHaveLength(pipelines.length);
});
describe('status cell', () => {
@@ -120,7 +111,7 @@ describe('Pipelines Table', () => {
});
it('should display the pipeline id', () => {
- expect(findPipelineInfo().text()).toContain(`#${pipeline.id}`);
+ expect(findPipelineInfo().text()).toContain(`#${firstPipeline.id}`);
});
});
@@ -130,24 +121,33 @@ describe('Pipelines Table', () => {
});
it('should render the right number of stages', () => {
- const stagesLength = pipeline.details.stages.length;
- expect(findLegacyPipelineMiniGraph().props('stages').length).toBe(stagesLength);
+ const stagesLength = firstPipeline.details.stages.length;
+ expect(findLegacyPipelineMiniGraph().props('stages')).toHaveLength(stagesLength);
});
it('should render the latest downstream pipelines only', () => {
// component receives two downstream pipelines. one of them is already outdated
// because we retried the trigger job, so the mini pipeline graph will only
// render the newly created downstream pipeline instead
- expect(pipeline.triggered).toHaveLength(2);
+ expect(firstPipeline.triggered).toHaveLength(2);
expect(findLegacyPipelineMiniGraph().props('downstreamPipelines')).toHaveLength(1);
});
describe('when pipeline does not have stages', () => {
beforeEach(() => {
- pipeline = createMockPipeline();
- pipeline.details.stages = [];
-
- createComponent({ pipelines: [pipeline] });
+ createComponent({
+ props: {
+ pipelines: [
+ {
+ ...firstPipeline,
+ details: {
+ ...firstPipeline.details,
+ stages: [],
+ },
+ },
+ ],
+ },
+ });
});
it('stages are not rendered', () => {
@@ -163,6 +163,10 @@ describe('Pipelines Table', () => {
});
describe('operations cell', () => {
+ beforeEach(() => {
+ createComponent({ stubs: { PipelineOperations } });
+ });
+
it('should render pipeline operations', () => {
expect(findActions().exists()).toBe(true);
});
@@ -186,11 +190,11 @@ describe('Pipelines Table', () => {
describe('row', () => {
describe('when the FF is disabled', () => {
beforeEach(() => {
- createComponent({ pipelines: [pipeline] });
+ createComponent();
});
it('does not render', () => {
- expect(findTableRows()).toHaveLength(1);
+ expect(findTableRows()).toHaveLength(pipelines.length);
expect(findPipelineFailureWidget().exists()).toBe(false);
});
});
@@ -198,20 +202,21 @@ describe('Pipelines Table', () => {
describe('when the FF is enabled', () => {
describe('and `withFailedJobsDetails` value is provided', () => {
beforeEach(() => {
- createComponent({ pipelines: [pipeline] }, provideWithDetails);
+ createComponent({ provide: provideWithDetails });
});
it('renders', () => {
- expect(findTableRows()).toHaveLength(2);
+ // We have 2 rows per pipeline with the widget
+ expect(findTableRows()).toHaveLength(pipelines.length * 2);
expect(findPipelineFailureWidget().exists()).toBe(true);
});
it('passes the expected props', () => {
expect(findPipelineFailureWidget().props()).toStrictEqual({
- failedJobsCount: pipeline.failed_builds.length,
- isPipelineActive: pipeline.active,
- pipelineIid: pipeline.iid,
- pipelinePath: pipeline.path,
+ failedJobsCount: firstPipeline.failed_builds.length,
+ isPipelineActive: firstPipeline.active,
+ pipelineIid: firstPipeline.iid,
+ pipelinePath: firstPipeline.path,
// Make sure the forward slash was removed
projectPath: 'frontend-fixtures/pipelines-project',
});
@@ -220,14 +225,13 @@ describe('Pipelines Table', () => {
describe('and `withFailedJobsDetails` value is not provided', () => {
beforeEach(() => {
- createComponent(
- { pipelines: [pipeline] },
- { glFeatures: { ciJobFailuresInMr: true } },
- );
+ createComponent({
+ provide: { glFeatures: { ciJobFailuresInMr: true } },
+ });
});
it('does not render', () => {
- expect(findTableRows()).toHaveLength(1);
+ expect(findTableRows()).toHaveLength(pipelines.length);
expect(findPipelineFailureWidget().exists()).toBe(false);
});
});
@@ -235,35 +239,55 @@ describe('Pipelines Table', () => {
});
});
- describe('tracking', () => {
+ describe('events', () => {
beforeEach(() => {
- trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ createComponent();
});
- afterEach(() => {
- unmockTracking();
+ describe('when confirming to cancel a pipeline', () => {
+ beforeEach(async () => {
+ await findActions().vm.$emit('cancel-pipeline', firstPipeline);
+ });
+
+ it('emits the `cancel-pipeline` event', () => {
+ expect(wrapper.emitted('cancel-pipeline')).toEqual([[firstPipeline]]);
+ });
});
- it('tracks status badge click', () => {
- findCiBadgeLink().vm.$emit('ciStatusBadgeClick');
+ describe('when retrying a pipeline', () => {
+ beforeEach(() => {
+ findActions().vm.$emit('retry-pipeline', firstPipeline);
+ });
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_ci_status_badge', {
- label: TRACKING_CATEGORIES.table,
+ it('emits the `retry-pipeline` event', () => {
+ expect(wrapper.emitted('retry-pipeline')).toEqual([[firstPipeline]]);
});
});
- it('tracks retry pipeline button click', () => {
- findRetryBtn().vm.$emit('click');
+ describe('when refreshing pipelines', () => {
+ beforeEach(() => {
+ findActions().vm.$emit('refresh-pipelines-table');
+ });
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry_button', {
- label: TRACKING_CATEGORIES.table,
+ it('emits the `refresh-pipelines-table` event', () => {
+ expect(wrapper.emitted('refresh-pipelines-table')).toEqual([[]]);
});
});
+ });
- it('tracks cancel pipeline button click', () => {
- findCancelBtn().vm.$emit('click');
+ describe('tracking', () => {
+ beforeEach(() => {
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
- expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_cancel_button', {
+ it('tracks status badge click', () => {
+ findCiBadgeLink().vm.$emit('ciStatusBadgeClick');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_ci_status_badge', {
label: TRACKING_CATEGORIES.table,
});
});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js
index d2eab64b317..6205a37e291 100644
--- a/spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_operations_spec.js
@@ -1,10 +1,13 @@
+import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import PipelinesManualActions from '~/ci/pipelines_page/components/pipelines_manual_actions.vue';
import PipelineMultiActions from '~/ci/pipelines_page/components/pipeline_multi_actions.vue';
import PipelineOperations from '~/ci/pipelines_page/components/pipeline_operations.vue';
-import eventHub from '~/ci/event_hub';
+import PipelineStopModal from '~/ci/pipelines_page/components/pipeline_stop_modal.vue';
+import { TRACKING_CATEGORIES } from '~/ci/constants';
describe('Pipeline operations', () => {
+ let trackingSpy;
let wrapper;
const defaultProps = {
@@ -36,6 +39,7 @@ describe('Pipeline operations', () => {
const findMultiActions = () => wrapper.findComponent(PipelineMultiActions);
const findRetryBtn = () => wrapper.findByTestId('pipelines-retry-button');
const findCancelBtn = () => wrapper.findByTestId('pipelines-cancel-button');
+ const findPipelineStopModal = () => wrapper.findComponent(PipelineStopModal);
it('should display pipeline manual actions', () => {
createComponent();
@@ -49,28 +53,71 @@ describe('Pipeline operations', () => {
expect(findMultiActions().exists()).toBe(true);
});
+ it('does not show the confirmation modal', () => {
+ createComponent();
+
+ expect(findPipelineStopModal().props().showConfirmationModal).toBe(false);
+ });
+
+ describe('when cancelling a pipeline', () => {
+ beforeEach(async () => {
+ createComponent();
+ await findCancelBtn().vm.$emit('click');
+ });
+
+ it('should show a confirmation modal', () => {
+ expect(findPipelineStopModal().props().showConfirmationModal).toBe(true);
+ });
+
+ it('should emit cancel-pipeline event when confirming', async () => {
+ await findPipelineStopModal().vm.$emit('submit');
+
+ expect(wrapper.emitted('cancel-pipeline')).toEqual([[defaultProps.pipeline]]);
+ expect(findPipelineStopModal().props().showConfirmationModal).toBe(false);
+ });
+
+ it('should hide the modal when closing', async () => {
+ await findPipelineStopModal().vm.$emit('close-modal');
+
+ expect(findPipelineStopModal().props().showConfirmationModal).toBe(false);
+ });
+ });
+
describe('events', () => {
beforeEach(() => {
createComponent();
-
- jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
});
it('should emit retryPipeline event', () => {
findRetryBtn().vm.$emit('click');
- expect(eventHub.$emit).toHaveBeenCalledWith(
- 'retryPipeline',
- defaultProps.pipeline.retry_path,
- );
+ expect(wrapper.emitted('retry-pipeline')).toEqual([[defaultProps.pipeline]]);
+ });
+ });
+
+ describe('tracking', () => {
+ beforeEach(() => {
+ createComponent();
+ trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
+ });
+
+ afterEach(() => {
+ unmockTracking();
+ });
+
+ it('tracks retry pipeline button click', () => {
+ findRetryBtn().vm.$emit('click');
+
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_retry_button', {
+ label: TRACKING_CATEGORIES.table,
+ });
});
- it('should emit openConfirmationModal event', () => {
+ it('tracks cancel pipeline button click', () => {
findCancelBtn().vm.$emit('click');
- expect(eventHub.$emit).toHaveBeenCalledWith('openConfirmationModal', {
- pipeline: defaultProps.pipeline,
- endpoint: defaultProps.pipeline.cancel_path,
+ expect(trackingSpy).toHaveBeenCalledWith(undefined, 'click_cancel_button', {
+ label: TRACKING_CATEGORIES.table,
});
});
});
diff --git a/spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js b/spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js
index 4d78a923542..1e276840c07 100644
--- a/spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js
+++ b/spec/frontend/ci/pipelines_page/components/pipeline_stop_modal_spec.js
@@ -1,15 +1,17 @@
import { shallowMount } from '@vue/test-utils';
-import { GlSprintf } from '@gitlab/ui';
+import { GlModal, GlSprintf } from '@gitlab/ui';
import { mockPipelineHeader } from 'jest/ci/pipeline_details/mock_data';
import PipelineStopModal from '~/ci/pipelines_page/components/pipeline_stop_modal.vue';
describe('PipelineStopModal', () => {
let wrapper;
- const createComponent = () => {
+ const createComponent = ({ props = {} } = {}) => {
wrapper = shallowMount(PipelineStopModal, {
propsData: {
pipeline: mockPipelineHeader,
+ showConfirmationModal: false,
+ ...props,
},
stubs: {
GlSprintf,
@@ -17,11 +19,43 @@ describe('PipelineStopModal', () => {
});
};
+ const findModal = () => wrapper.findComponent(GlModal);
+
beforeEach(() => {
createComponent();
});
- it('should render "stop pipeline" warning', () => {
- expect(wrapper.text()).toMatch(`You’re about to stop pipeline #${mockPipelineHeader.id}.`);
+ describe('when `showConfirmationModal` is false', () => {
+ it('passes the visiblity value to the modal', () => {
+ expect(findModal().props().visible).toBe(false);
+ });
+ });
+
+ describe('when `showConfirmationModal` is true', () => {
+ beforeEach(() => {
+ createComponent({ props: { showConfirmationModal: true } });
+ });
+
+ it('passes the visiblity value to the modal', () => {
+ expect(findModal().props().visible).toBe(true);
+ });
+
+ it('renders "stop pipeline" warning', () => {
+ expect(wrapper.text()).toMatch(`You're about to stop pipeline #${mockPipelineHeader.id}.`);
+ });
+ });
+
+ describe('events', () => {
+ beforeEach(() => {
+ createComponent({ props: { showConfirmationModal: true } });
+ });
+
+ it('emits the close-modal event when the visiblity changes', async () => {
+ expect(wrapper.emitted('close-modal')).toBeUndefined();
+
+ await findModal().vm.$emit('change', false);
+
+ expect(wrapper.emitted('close-modal')).toEqual([[]]);
+ });
});
});
diff --git a/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js b/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js
index 4af292e3588..d58b139dae3 100644
--- a/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js
+++ b/spec/frontend/commit/pipelines/legacy_pipelines_table_wrapper_spec.js
@@ -1,13 +1,13 @@
import { GlLoadingIcon, GlModal, GlTableLite } from '@gitlab/ui';
-import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import fixture from 'test_fixtures/pipelines/pipelines.json';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { stubComponent } from 'helpers/stub_component';
import waitForPromises from 'helpers/wait_for_promises';
import Api from '~/api';
-import LegacyPipelinesTableWraper from '~/commit/pipelines/legacy_pipelines_table_wrapper.vue';
+import LegacyPipelinesTableWrapper from '~/commit/pipelines/legacy_pipelines_table_wrapper.vue';
+import PipelinesTable from '~/ci/common/pipelines_table.vue';
import {
HTTP_STATUS_BAD_REQUEST,
HTTP_STATUS_INTERNAL_SERVER_ERROR,
@@ -39,27 +39,26 @@ describe('Pipelines table in Commits and Merge requests', () => {
const findTableRows = () => wrapper.findAllByTestId('pipeline-table-row');
const findModal = () => wrapper.findComponent(GlModal);
const findMrPipelinesDocsLink = () => wrapper.findByTestId('mr-pipelines-docs-link');
-
- const createComponent = ({ props = {} } = {}) => {
- wrapper = extendedWrapper(
- mount(LegacyPipelinesTableWraper, {
- propsData: {
- endpoint: 'endpoint.json',
- emptyStateSvgPath: 'foo',
- errorStateSvgPath: 'foo',
- ...props,
- },
- mocks: {
- $toast,
- },
- stubs: {
- GlModal: stubComponent(GlModal, {
- template: '<div />',
- methods: { show: showMock },
- }),
- },
- }),
- );
+ const findPipelinesTable = () => wrapper.findComponent(PipelinesTable);
+
+ const createComponent = ({ props = {}, mountFn = mountExtended } = {}) => {
+ wrapper = mountFn(LegacyPipelinesTableWrapper, {
+ propsData: {
+ endpoint: 'endpoint.json',
+ emptyStateSvgPath: 'foo',
+ errorStateSvgPath: 'foo',
+ ...props,
+ },
+ mocks: {
+ $toast,
+ },
+ stubs: {
+ GlModal: stubComponent(GlModal, {
+ template: '<div />',
+ methods: { show: showMock },
+ }),
+ },
+ });
};
beforeEach(() => {
@@ -116,7 +115,6 @@ describe('Pipelines table in Commits and Merge requests', () => {
it('should make an API request when using pagination', async () => {
expect(mock.history.get).toHaveLength(1);
- expect(mock.history.get[0].params.page).toBe('1');
wrapper.find('.next-page-item').trigger('click');
@@ -359,4 +357,53 @@ describe('Pipelines table in Commits and Merge requests', () => {
);
});
});
+
+ describe('events', () => {
+ beforeEach(async () => {
+ mock.onGet('endpoint.json').reply(HTTP_STATUS_OK, [pipeline]);
+
+ createComponent({ mountFn: shallowMountExtended });
+
+ await waitForPromises();
+ });
+
+ describe('When cancelling a pipeline', () => {
+ it('sends the cancel action', async () => {
+ expect(mock.history.post).toHaveLength(0);
+
+ findPipelinesTable().vm.$emit('cancel-pipeline', pipeline);
+
+ await waitForPromises();
+
+ expect(mock.history.post).toHaveLength(1);
+ expect(mock.history.post[0].url).toContain('cancel.json');
+ });
+ });
+
+ describe('When retrying a pipeline', () => {
+ it('sends the retry action', async () => {
+ expect(mock.history.post).toHaveLength(0);
+
+ findPipelinesTable().vm.$emit('retry-pipeline', pipeline);
+
+ await waitForPromises();
+
+ expect(mock.history.post).toHaveLength(1);
+ expect(mock.history.post[0].url).toContain('retry.json');
+ });
+ });
+
+ describe('When refreshing a pipeline', () => {
+ it('calls the pipelines endpoint again', async () => {
+ expect(mock.history.get).toHaveLength(1);
+
+ findPipelinesTable().vm.$emit('refresh-pipelines-table');
+
+ await waitForPromises();
+
+ expect(mock.history.get).toHaveLength(2);
+ expect(mock.history.get[1].url).toContain('endpoint.json');
+ });
+ });
+ });
});