Commit 755fdd44 authored by Adam Hegyi's avatar Adam Hegyi

Remove CI builds for test and staging stages in VSA

Remove special case for test and staging stages in Value Stream
Analytics. This also fixes the cross-join with the CI tables.

Changelog: changed
parent 70a62f99
......@@ -17,8 +17,6 @@ import {
PAGINATION_SORT_FIELD_DURATION,
PAGINATION_SORT_DIRECTION_ASC,
PAGINATION_SORT_DIRECTION_DESC,
STAGE_TITLE_STAGING,
STAGE_TITLE_TEST,
} from '../constants';
import TotalTime from './total_time_component.vue';
......@@ -107,28 +105,12 @@ export default {
emptyStateTitleText() {
return this.emptyStateTitle || NOT_ENOUGH_DATA_ERROR;
},
isDefaultTestStage() {
const { selectedStage } = this;
return (
!selectedStage.custom && selectedStage.title?.toLowerCase().trim() === STAGE_TITLE_TEST
);
},
isDefaultStagingStage() {
const { selectedStage } = this;
return (
!selectedStage.custom && selectedStage.title?.toLowerCase().trim() === STAGE_TITLE_STAGING
);
},
isMergeRequestStage() {
const [firstEvent] = this.stageEvents;
return this.isMrLink(firstEvent.url);
},
workflowTitle() {
if (this.isDefaultTestStage) {
return WORKFLOW_COLUMN_TITLES.jobs;
} else if (this.isDefaultStagingStage) {
return WORKFLOW_COLUMN_TITLES.deployments;
} else if (this.isMergeRequestStage) {
if (this.isMergeRequestStage) {
return WORKFLOW_COLUMN_TITLES.mergeRequests;
}
return WORKFLOW_COLUMN_TITLES.issues;
......@@ -209,22 +191,6 @@ export default {
<div data-testid="vsa-stage-event">
<div v-if="item.id" data-testid="vsa-stage-content">
<p class="gl-m-0">
<template v-if="isDefaultTestStage">
<span
class="icon-build-status gl-vertical-align-middle gl-text-green-500"
data-testid="vsa-stage-event-build-status"
>
<gl-icon name="status_success" :size="14" />
</span>
<gl-link
class="gl-text-black-normal item-build-name"
data-testid="vsa-stage-event-build-name"
:href="item.url"
>
{{ item.name }}
</gl-link>
&middot;
</template>
<gl-link class="gl-text-black-normal pipeline-id" :href="item.url"
>#{{ item.id }}</gl-link
>
......@@ -246,12 +212,7 @@ export default {
>
</p>
<p class="gl-m-0">
<span v-if="isDefaultTestStage" data-testid="vsa-stage-event-build-status-date">
<gl-link class="gl-text-black-normal issue-date" :href="item.url">{{
item.date
}}</gl-link>
</span>
<span v-else data-testid="vsa-stage-event-build-author-and-date">
<span data-testid="vsa-stage-event-build-author-and-date">
<gl-link class="gl-text-black-normal build-date" :href="item.url">{{
item.date
}}</gl-link>
......
......@@ -20,9 +20,6 @@ export const PAGINATION_SORT_FIELD_DURATION = 'duration';
export const PAGINATION_SORT_DIRECTION_DESC = 'desc';
export const PAGINATION_SORT_DIRECTION_ASC = 'asc';
export const STAGE_TITLE_STAGING = 'staging';
export const STAGE_TITLE_TEST = 'test';
export const I18N_VSA_ERROR_STAGES = __(
'There was an error fetching value stream analytics stages.',
);
......
......@@ -38,22 +38,6 @@ module Gitlab
# rubocop: disable CodeReuse/ActiveRecord
def serialized_records
strong_memoize(:serialized_records) do
# special case (legacy): 'Test' and 'Staging' stages should show Ci::Build records
if default_test_stage? || default_staging_stage?
ci_build_join = mr_metrics_table
.join(build_table)
.on(mr_metrics_table[:pipeline_id].eq(build_table[:commit_id]))
.join_sources
records = ordered_and_limited_query
.joins(ci_build_join)
.select(build_table[:id], *time_columns)
yield records if block_given?
ci_build_records = preload_ci_build_associations(records)
AnalyticsBuildSerializer.new.represent(ci_build_records.map { |e| e['build'] })
else
records = ordered_and_limited_query.select(*columns, *time_columns)
yield records if block_given?
......@@ -70,7 +54,6 @@ module Gitlab
end
end
end
end
# rubocop: enable CodeReuse/ActiveRecord
private
......@@ -83,26 +66,10 @@ module Gitlab
end
end
def default_test_stage?
stage.matches_with_stage_params?(Gitlab::Analytics::CycleAnalytics::DefaultStages.params_for_test_stage)
end
def default_staging_stage?
stage.matches_with_stage_params?(Gitlab::Analytics::CycleAnalytics::DefaultStages.params_for_staging_stage)
end
def serializer
MAPPINGS.fetch(subject_class).fetch(:serializer_class).new
end
# rubocop: disable CodeReuse/ActiveRecord
def preload_ci_build_associations(records)
results = records.map(&:attributes)
Gitlab::CycleAnalytics::Updater.update!(results, from: 'id', to: 'build', klass: ::Ci::Build.includes({ project: [:namespace], user: [], pipeline: [] }))
end
# rubocop: enable CodeReuse/ActiveRecord
def ordered_and_limited_query
strong_memoize(:ordered_and_limited_query) do
order_by(query, sort, direction, columns).page(page).per(per_page).without_count
......
......@@ -77,13 +77,13 @@ RSpec.describe 'Value Stream Analytics', :js do
expect_merge_request_to_be_present
click_stage('Test')
expect_build_to_be_present
expect_merge_request_to_be_present
click_stage('Review')
expect_merge_request_to_be_present
click_stage('Staging')
expect_build_to_be_present
expect_merge_request_to_be_present
end
context "when I change the time period observed" do
......@@ -160,12 +160,6 @@ RSpec.describe 'Value Stream Analytics', :js do
expect(find(stage_table_selector)).to have_content("##{issue.iid}")
end
def expect_build_to_be_present
expect(find(stage_table_selector)).to have_content(@build.ref)
expect(find(stage_table_selector)).to have_content(@build.short_sha)
expect(find(stage_table_selector)).to have_content("##{@build.id}")
end
def expect_merge_request_to_be_present
expect(find(stage_table_selector)).to have_content(mr.title)
expect(find(stage_table_selector)).to have_content(mr.author.name)
......
......@@ -132,8 +132,6 @@ export const convertedData = {
export const rawIssueEvents = stageFixtures.issue;
export const issueEvents = deepCamelCase(rawIssueEvents);
export const reviewEvents = deepCamelCase(stageFixtures.review);
export const testEvents = deepCamelCase(stageFixtures.test);
export const stagingEvents = deepCamelCase(stageFixtures.staging);
export const pathNavIssueMetric = 172800;
......
......@@ -4,16 +4,7 @@ import { mockTracking, unmockTracking } from 'helpers/tracking_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import StageTable from '~/cycle_analytics/components/stage_table.vue';
import { PAGINATION_SORT_FIELD_DURATION } from '~/cycle_analytics/constants';
import {
stagingEvents,
stagingStage,
issueEvents,
issueStage,
testEvents,
testStage,
reviewStage,
reviewEvents,
} from './mock_data';
import { issueEvents, issueStage, reviewStage, reviewEvents } from './mock_data';
let wrapper = null;
let trackingSpy = null;
......@@ -22,12 +13,8 @@ const noDataSvgPath = 'path/to/no/data';
const emptyStateTitle = 'Too much data';
const notEnoughDataError = "We don't have enough data to show this stage.";
const issueEventItems = issueEvents.events;
const stagingEventItems = stagingEvents.events;
const testEventItems = testEvents.events;
const reviewEventItems = reviewEvents.events;
const [firstIssueEvent] = issueEventItems;
const [firstStagingEvent] = stagingEventItems;
const [firstTestEvent] = testEventItems;
const [firstReviewEvent] = reviewEventItems;
const pagination = { page: 1, hasNextPage: true };
......@@ -156,99 +143,6 @@ describe('StageTable', () => {
});
});
describe('staging event', () => {
beforeEach(() => {
wrapper = createComponent({
stageEvents: [{ ...firstStagingEvent }],
selectedStage: { ...stagingStage, custom: false },
});
});
it('will set the workflow title to "Deployments"', () => {
expect(findTableHead().text()).toContain('Deployments');
expect(findTableHead().text()).not.toContain('Issues');
});
it('will not render the event title', () => {
expect(wrapper.findByTestId('vsa-stage-event-title').exists()).toBe(false);
});
it('will render the fork icon', () => {
expect(findIcon('fork').exists()).toBe(true);
});
it('will render the branch icon', () => {
expect(findIcon('commit').exists()).toBe(true);
});
it('will render the total time', () => {
expect(findStageTime().text()).toBe('2 mins');
});
it('will render the build shortSha', () => {
expect(wrapper.findByTestId('vsa-stage-event-build-sha').text()).toBe(
firstStagingEvent.shortSha,
);
});
it('will render the author and date', () => {
const content = wrapper.findByTestId('vsa-stage-event-build-author-and-date').text();
expect(content).toContain(firstStagingEvent.author.name);
expect(content).toContain(firstStagingEvent.date);
});
});
describe('test event', () => {
beforeEach(() => {
wrapper = createComponent({
stageEvents: [{ ...firstTestEvent }],
selectedStage: { ...testStage, custom: false },
});
});
it('will set the workflow title to "Jobs"', () => {
expect(findTableHead().text()).toContain('Jobs');
expect(findTableHead().text()).not.toContain('Issues');
});
it('will not render the event title', () => {
expect(wrapper.findByTestId('vsa-stage-event-title').exists()).toBe(false);
});
it('will render the fork icon', () => {
expect(findIcon('fork').exists()).toBe(true);
});
it('will render the branch icon', () => {
expect(findIcon('commit').exists()).toBe(true);
});
it('will render the total time', () => {
expect(findStageTime().text()).toBe('2 mins');
});
it('will render the build shortSha', () => {
expect(wrapper.findByTestId('vsa-stage-event-build-sha').text()).toBe(
firstTestEvent.shortSha,
);
});
it('will render the build pipeline success icon', () => {
expect(wrapper.findByTestId('status_success-icon').exists()).toBe(true);
});
it('will render the build date', () => {
const content = wrapper.findByTestId('vsa-stage-event-build-status-date').text();
expect(content).toContain(firstTestEvent.date);
});
it('will render the build event name', () => {
expect(wrapper.findByTestId('vsa-stage-event-build-name').text()).toContain(
firstTestEvent.name,
);
});
});
describe('isLoading = true', () => {
beforeEach(() => {
wrapper = createComponent({ isLoading: true }, true);
......
......@@ -79,56 +79,6 @@ RSpec.describe Gitlab::Analytics::CycleAnalytics::RecordsFetcher do
include_context 'when records are loaded by maintainer'
end
describe 'special case' do
let(:mr1) { create(:merge_request, source_project: project, allow_broken: true, created_at: 20.days.ago) }
let(:mr2) { create(:merge_request, source_project: project, allow_broken: true, created_at: 19.days.ago) }
let(:ci_build1) { create(:ci_build) }
let(:ci_build2) { create(:ci_build) }
let(:default_stages) { Gitlab::Analytics::CycleAnalytics::DefaultStages }
let(:stage) { build(:cycle_analytics_project_stage, default_stages.params_for_test_stage.merge(project: project)) }
before do
mr1.metrics.update!({
merged_at: 5.days.ago,
first_deployed_to_production_at: 1.day.ago,
latest_build_started_at: 5.days.ago,
latest_build_finished_at: 1.day.ago,
pipeline: ci_build1.pipeline
})
mr2.metrics.update!({
merged_at: 10.days.ago,
first_deployed_to_production_at: 5.days.ago,
latest_build_started_at: 9.days.ago,
latest_build_finished_at: 7.days.ago,
pipeline: ci_build2.pipeline
})
project.add_user(user, Gitlab::Access::MAINTAINER)
end
context 'returns build records' do
shared_examples 'orders build records by `latest_build_finished_at`' do
it 'orders by `latest_build_finished_at`' do
build_ids = subject.map { |item| item[:id] }
expect(build_ids).to eq([ci_build1.id, ci_build2.id])
end
end
context 'when requesting records for default test stage' do
include_examples 'orders build records by `latest_build_finished_at`'
end
context 'when requesting records for default staging stage' do
before do
stage.assign_attributes(default_stages.params_for_staging_stage)
end
include_examples 'orders build records by `latest_build_finished_at`'
end
end
end
end
describe 'pagination' do
......
......@@ -8,6 +8,9 @@ RSpec.describe 'value stream analytics events' do
let(:issue) { create(:issue, project: project, created_at: 2.days.ago) }
describe 'GET /:namespace/:project/value_stream_analytics/events/issues' do
let(:first_issue_iid) { project.issues.sort_by_attribute(:created_desc).pluck(:iid).first.to_s }
let(:first_mr_iid) { project.merge_requests.sort_by_attribute(:created_desc).pluck(:iid).first.to_s }
before do
project.add_developer(user)
......@@ -25,8 +28,6 @@ RSpec.describe 'value stream analytics events' do
it 'lists the issue events' do
get project_cycle_analytics_issue_path(project, format: :json)
first_issue_iid = project.issues.sort_by_attribute(:created_desc).pluck(:iid).first.to_s
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['iid']).to eq(first_issue_iid)
end
......@@ -34,8 +35,6 @@ RSpec.describe 'value stream analytics events' do
it 'lists the plan events' do
get project_cycle_analytics_plan_path(project, format: :json)
first_issue_iid = project.issues.sort_by_attribute(:created_desc).pluck(:iid).first.to_s
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['iid']).to eq(first_issue_iid)
end
......@@ -45,8 +44,6 @@ RSpec.describe 'value stream analytics events' do
expect(json_response['events']).not_to be_empty
first_mr_iid = project.merge_requests.sort_by_attribute(:created_desc).pluck(:iid).first.to_s
expect(json_response['events'].first['iid']).to eq(first_mr_iid)
end
......@@ -54,15 +51,15 @@ RSpec.describe 'value stream analytics events' do
get project_cycle_analytics_test_path(project, format: :json)
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['date']).not_to be_empty
expect(json_response['events'].first['iid']).to eq(first_mr_iid)
end
it 'lists the review events' do
get project_cycle_analytics_review_path(project, format: :json)
first_mr_iid = project.merge_requests.sort_by_attribute(:created_desc).pluck(:iid).first.to_s
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['iid']).to eq(first_mr_iid)
end
......@@ -70,7 +67,8 @@ RSpec.describe 'value stream analytics events' do
get project_cycle_analytics_staging_path(project, format: :json)
expect(json_response['events']).not_to be_empty
expect(json_response['events'].first['date']).not_to be_empty
expect(json_response['events'].first['iid']).to eq(first_issue_iid)
end
context 'with private project and builds' do
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment