Commit 232b383a authored by Vladimir Shushlin's avatar Vladimir Shushlin Committed by Oswaldo Ferreira

Add pipeline parameter to evidence creation service

It's unused right now, but it will be used to collect
report artifacts related to this pipeline
parent d7ba793d
...@@ -41,16 +41,20 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -41,16 +41,20 @@ class Projects::TagsController < Projects::ApplicationController
# rubocop: enable CodeReuse/ActiveRecord # rubocop: enable CodeReuse/ActiveRecord
def create def create
# TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
evidence_pipeline = find_evidence_pipeline
result = ::Tags::CreateService.new(@project, current_user) result = ::Tags::CreateService.new(@project, current_user)
.execute(params[:tag_name], params[:ref], params[:message]) .execute(params[:tag_name], params[:ref], params[:message])
if result[:status] == :success if result[:status] == :success
# Release creation with Tags was deprecated in GitLab 11.7 # TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
if params[:release_description].present? if params[:release_description].present?
release_params = { release_params = {
tag: params[:tag_name], tag: params[:tag_name],
name: params[:tag_name], name: params[:tag_name],
description: params[:release_description] description: params[:release_description],
evidence_pipeline: evidence_pipeline
} }
Releases::CreateService Releases::CreateService
...@@ -93,4 +97,14 @@ class Projects::TagsController < Projects::ApplicationController ...@@ -93,4 +97,14 @@ class Projects::TagsController < Projects::ApplicationController
end end
end end
end end
private
# TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
def find_evidence_pipeline
evidence_pipeline_sha = @project.repository.commit(params[:ref])&.sha
return unless evidence_pipeline_sha
@project.ci_pipelines.for_sha(evidence_pipeline_sha).last
end
end end
...@@ -2,8 +2,9 @@ ...@@ -2,8 +2,9 @@
module Releases module Releases
class CreateEvidenceService class CreateEvidenceService
def initialize(release) def initialize(release, pipeline: nil)
@release = release @release = release
@pipeline = pipeline
end end
def execute def execute
......
...@@ -9,11 +9,16 @@ module Releases ...@@ -9,11 +9,16 @@ module Releases
return error('Release already exists', 409) if release return error('Release already exists', 409) if release
return error("Milestone(s) not found: #{inexistent_milestones.join(', ')}", 400) if inexistent_milestones.any? return error("Milestone(s) not found: #{inexistent_milestones.join(', ')}", 400) if inexistent_milestones.any?
# should be found before the creation of new tag
# because tag creation can spawn new pipeline
# which won't have any data for evidence yet
evidence_pipeline = find_evidence_pipeline
tag = ensure_tag tag = ensure_tag
return tag unless tag.is_a?(Gitlab::Git::Tag) return tag unless tag.is_a?(Gitlab::Git::Tag)
create_release(tag) create_release(tag, evidence_pipeline)
end end
def find_or_build_release def find_or_build_release
...@@ -42,14 +47,14 @@ module Releases ...@@ -42,14 +47,14 @@ module Releases
Ability.allowed?(current_user, :create_release, project) Ability.allowed?(current_user, :create_release, project)
end end
def create_release(tag) def create_release(tag, evidence_pipeline)
release = build_release(tag) release = build_release(tag)
release.save! release.save!
notify_create_release(release) notify_create_release(release)
create_evidence!(release) create_evidence!(release, evidence_pipeline)
success(tag: tag, release: release) success(tag: tag, release: release)
rescue => e rescue => e
...@@ -73,13 +78,25 @@ module Releases ...@@ -73,13 +78,25 @@ module Releases
) )
end end
def create_evidence!(release) def find_evidence_pipeline
# TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
return params[:evidence_pipeline] if params[:evidence_pipeline]
sha = existing_tag&.dereferenced_target&.sha
sha ||= repository.commit(ref)&.sha
return unless sha
project.ci_pipelines.for_sha(sha).last
end
def create_evidence!(release, pipeline)
return if release.historical_release? return if release.historical_release?
if release.upcoming_release? if release.upcoming_release?
CreateEvidenceWorker.perform_at(release.released_at, release.id) CreateEvidenceWorker.perform_at(release.released_at, release.id, pipeline&.id)
else else
CreateEvidenceWorker.perform_async(release.id) CreateEvidenceWorker.perform_async(release.id, pipeline&.id)
end end
end end
end end
......
...@@ -6,10 +6,15 @@ class CreateEvidenceWorker # rubocop:disable Scalability/IdempotentWorker ...@@ -6,10 +6,15 @@ class CreateEvidenceWorker # rubocop:disable Scalability/IdempotentWorker
feature_category :release_evidence feature_category :release_evidence
weight 2 weight 2
def perform(release_id) # pipeline_id is optional for backward compatibility with existing jobs
# caller should always try to provide the pipeline and pass nil only
# if pipeline is absent
def perform(release_id, pipeline_id = nil)
release = Release.find_by_id(release_id) release = Release.find_by_id(release_id)
return unless release return unless release
::Releases::CreateEvidenceService.new(release).execute pipeline = Ci::Pipeline.find_by_id(pipeline_id)
::Releases::CreateEvidenceService.new(release, pipeline: pipeline).execute
end end
end end
...@@ -6,6 +6,7 @@ RSpec.describe Projects::TagsController do ...@@ -6,6 +6,7 @@ RSpec.describe Projects::TagsController do
let(:project) { create(:project, :public, :repository) } let(:project) { create(:project, :public, :repository) }
let!(:release) { create(:release, project: project) } let!(:release) { create(:release, project: project) }
let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') } let!(:invalid_release) { create(:release, project: project, tag: 'does-not-exist') }
let(:user) { create(:user) }
describe 'GET index' do describe 'GET index' do
before do before do
...@@ -61,4 +62,69 @@ RSpec.describe Projects::TagsController do ...@@ -61,4 +62,69 @@ RSpec.describe Projects::TagsController do
end end
end end
end end
describe 'POST #create' do
before do
project.add_developer(user)
sign_in(user)
end
let(:release_description) { nil }
let(:request) do
post(:create, params: {
namespace_id: project.namespace.to_param,
project_id: project,
tag_name: '1.0',
ref: 'master',
release_description: release_description
})
end
it 'creates tag' do
request
expect(response).to have_gitlab_http_status(:found)
expect(project.repository.find_tag('1.0')).to be_present
end
# TODO: remove this with the release creation moved to it's own form https://gitlab.com/gitlab-org/gitlab/-/issues/214245
context 'when release description is set' do
let(:release_description) { 'some release description' }
it 'creates tag and release' do
request
expect(response).to have_gitlab_http_status(:found)
expect(project.repository.find_tag('1.0')).to be_present
release = project.releases.find_by_tag!('1.0')
expect(release).to be_present
expect(release.description).to eq(release_description)
end
it 'passes the last pipeline for evidence creation', :sidekiq_inline do
sha = project.repository.commit('master').sha
create(:ci_empty_pipeline, sha: sha, project: project) # old pipeline
pipeline = create(:ci_empty_pipeline, sha: sha, project: project)
# simulating pipeline creation by new tag
expect_any_instance_of(Repository).to receive(:add_tag).and_wrap_original do |m, *args|
create(:ci_empty_pipeline, sha: sha, project: project)
m.call(*args)
end
expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service|
expect(service).to receive(:execute).and_call_original
end
request
release = project.releases.find_by_tag!('1.0')
expect(release).to be_present
expect(release.description).to eq(release_description)
end
end
end
end end
...@@ -188,6 +188,7 @@ describe Releases::CreateService do ...@@ -188,6 +188,7 @@ describe Releases::CreateService do
end end
context 'Evidence collection' do context 'Evidence collection' do
let(:sha) { project.repository.commit('master').sha }
let(:params) do let(:params) do
{ {
name: 'New release', name: 'New release',
...@@ -229,6 +230,75 @@ describe Releases::CreateService do ...@@ -229,6 +230,75 @@ describe Releases::CreateService do
end end
end end
shared_examples 'uses the right pipeline for evidence' do
it 'creates evidence without pipeline if it does not exist', :sidekiq_inline do
expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: nil) do |service|
expect(service).to receive(:execute).and_call_original
end
expect { subject }.to change(Releases::Evidence, :count).by(1)
end
it 'uses the last pipeline for evidence', :sidekiq_inline do
create(:ci_empty_pipeline, sha: sha, project: project) # old pipeline
pipeline = create(:ci_empty_pipeline, sha: sha, project: project)
expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service|
expect(service).to receive(:execute).and_call_original
end
expect { subject }.to change(Releases::Evidence, :count).by(1)
end
context 'when old evidence_pipeline is passed to service' do
let!(:old_pipeline) { create(:ci_empty_pipeline, sha: sha, project: project) }
let!(:new_pipeline) { create(:ci_empty_pipeline, sha: sha, project: project) }
let(:params) do
super().merge(
evidence_pipeline: old_pipeline
)
end
it 'uses the old pipeline for evidence', :sidekiq_inline do
expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: old_pipeline) do |service|
expect(service).to receive(:execute).and_call_original
end
expect { subject }.to change(Releases::Evidence, :count).by(1)
end
end
it 'pipeline is still being used for evidence if new pipeline is being created for tag', :sidekiq_inline do
pipeline = create(:ci_empty_pipeline, sha: sha, project: project)
expect(project.repository).to receive(:add_tag).and_wrap_original do |m, *args|
create(:ci_empty_pipeline, sha: sha, project: project)
m.call(*args)
end
expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service|
expect(service).to receive(:execute).and_call_original
end
expect { subject }.to change(Releases::Evidence, :count).by(1)
end
it 'uses the last pipeline for evidence when tag is already created', :sidekiq_inline do
Tags::CreateService.new(project, user).execute('v0.1', 'master', nil)
expect(project.repository.find_tag('v0.1')).to be_present
create(:ci_empty_pipeline, sha: sha, project: project) # old pipeline
pipeline = create(:ci_empty_pipeline, sha: sha, project: project)
expect_next_instance_of(Releases::CreateEvidenceService, anything, pipeline: pipeline) do |service|
expect(service).to receive(:execute).and_call_original
end
expect { subject }.to change(Releases::Evidence, :count).by(1)
end
end
context 'immediate release' do context 'immediate release' do
let(:released_at) { nil } let(:released_at) { nil }
...@@ -257,6 +327,8 @@ describe Releases::CreateService do ...@@ -257,6 +327,8 @@ describe Releases::CreateService do
expect(last_release.upcoming_release?).to be_falsy expect(last_release.upcoming_release?).to be_falsy
end end
include_examples 'uses the right pipeline for evidence'
end end
context 'upcoming release' do context 'upcoming release' do
...@@ -287,6 +359,8 @@ describe Releases::CreateService do ...@@ -287,6 +359,8 @@ describe Releases::CreateService do
expect(last_release.upcoming_release?).to be_truthy expect(last_release.upcoming_release?).to be_truthy
end end
include_examples 'uses the right pipeline for evidence'
end end
end end
end end
...@@ -3,13 +3,24 @@ ...@@ -3,13 +3,24 @@
require 'spec_helper' require 'spec_helper'
describe CreateEvidenceWorker do describe CreateEvidenceWorker do
let(:release) { create(:release) } let(:project) { create(:project, :repository) }
let(:release) { create(:release, project: project) }
let(:pipeline) { create(:ci_empty_pipeline, sha: release.sha, project: project) }
# support old scheduled workers without pipeline
it 'creates a new Evidence record' do it 'creates a new Evidence record' do
expect_next_instance_of(::Releases::CreateEvidenceService, release) do |service| expect_next_instance_of(::Releases::CreateEvidenceService, release, pipeline: nil) do |service|
expect(service).to receive(:execute).and_call_original expect(service).to receive(:execute).and_call_original
end end
expect { described_class.new.perform(release.id) }.to change(Releases::Evidence, :count).by(1) expect { described_class.new.perform(release.id) }.to change(Releases::Evidence, :count).by(1)
end end
it 'creates a new Evidence record with pipeline' do
expect_next_instance_of(::Releases::CreateEvidenceService, release, pipeline: pipeline) do |service|
expect(service).to receive(:execute).and_call_original
end
expect { described_class.new.perform(release.id, pipeline.id) }.to change(Releases::Evidence, :count).by(1)
end
end end
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