Commit c478e875 authored by Mehmet Emin INAC's avatar Mehmet Emin INAC

Always set the `latest_pipeline_id` in StoreReportsService

We should always set the latest_pipeline_id for the projects regardless
of the ingestion result.
parent 899686aa
......@@ -38,6 +38,32 @@ module Vulnerabilities
letter_grades[:a]
end
end
def set_latest_pipeline_with(pipeline)
upsert_sql = upsert_latest_pipeline_id_sql(pipeline)
connection.execute(upsert_sql)
end
private
UPSERT_LATEST_PIPELINE_ID_SQL_TEMPLATE = <<~SQL
INSERT INTO %<table_name>s AS target (project_id, latest_pipeline_id, letter_grade, created_at, updated_at)
VALUES (%{project_id}, %<latest_pipeline_id>d, %<letter_grade>d, now(), now())
ON CONFLICT (project_id)
DO UPDATE SET
latest_pipeline_id = %<latest_pipeline_id>d, updated_at = now()
SQL
private_constant :UPSERT_LATEST_PIPELINE_ID_SQL_TEMPLATE
def upsert_latest_pipeline_id_sql(pipeline)
format(UPSERT_LATEST_PIPELINE_ID_SQL_TEMPLATE,
table_name: table_name,
project_id: pipeline.project.id,
latest_pipeline_id: pipeline.id,
letter_grade: letter_grades[:a])
end
end
private
......
......@@ -12,7 +12,7 @@ module Security
def execute
store_reports
mark_project_as_vulnerable!
update_latest_pipeline_id!
set_latest_pipeline!
errors.any? ? error(full_errors) : success
end
......@@ -34,11 +34,8 @@ module Security
project.project_setting.update!(has_vulnerabilities: true)
end
def update_latest_pipeline_id!
# We are resetting/reloading the `project` record because the `vulnerability_statistic` association
# is created by an UPSERT query which does not set the association of the record.
# Also, the safe navigation is necessary in case if we can't save any vulnerability records.
project.reset.vulnerability_statistic&.update_column(:latest_pipeline_id, pipeline.id)
def set_latest_pipeline!
Vulnerabilities::Statistic.set_latest_pipeline_with(pipeline)
end
def full_errors
......
......@@ -46,4 +46,26 @@ RSpec.describe Vulnerabilities::Statistic do
it { is_expected.to eq(3) }
end
end
describe '.set_latest_pipeline_with' do
let_it_be(:pipeline) { create(:ci_pipeline) }
let_it_be(:project) { pipeline.project }
subject(:set_latest_pipeline) { described_class.set_latest_pipeline_with(pipeline) }
context 'when there is already a vulnerability_statistic record available for the project of given pipeline' do
let(:vulnerability_statistic) { create(:vulnerability_statistic, project: project) }
it 'updates the `latest_pipeline_id` attribute of the existing record' do
expect { set_latest_pipeline }.to change { vulnerability_statistic.reload.pipeline }.from(nil).to(pipeline)
end
end
context 'when there is no vulnerability_statistic record available for the project of given pipeline' do
it 'creates a new record with the `latest_pipeline_id` attribute is set' do
expect { set_latest_pipeline }.to change { project.reload.vulnerability_statistic }.from(nil).to(an_instance_of(described_class))
.and change { project.vulnerability_statistic&.pipeline }.from(nil).to(pipeline)
end
end
end
end
......@@ -34,7 +34,7 @@ RSpec.describe Security::StoreReportsService do
end
it 'marks the project as vulnerable' do
expect { execute_service_object }.to change { project.project_setting.has_vulnerabilities }.from(false).to(true)
expect { execute_service_object }.to change { project.reload.project_setting.has_vulnerabilities }.from(false).to(true)
end
it 'updates the `latest_pipeline_id` attribute of the associated `vulnerability_statistic` record' 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