Commit 35c0c524 authored by Shinya Maeda's avatar Shinya Maeda

Merge branch '199250-expose-release-yaml-as-steps-via-api' into 'master'

Expose `:release` yaml as steps via API

See merge request gitlab-org/gitlab!27810
parents 60072cbe 33630bb8
...@@ -26,7 +26,8 @@ module Ci ...@@ -26,7 +26,8 @@ module Ci
RUNNER_FEATURES = { RUNNER_FEATURES = {
upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? }, upload_multiple_artifacts: -> (build) { build.publishes_artifacts_reports? },
refspecs: -> (build) { build.merge_request_ref? }, refspecs: -> (build) { build.merge_request_ref? },
artifacts_exclude: -> (build) { build.supports_artifacts_exclude? } artifacts_exclude: -> (build) { build.supports_artifacts_exclude? },
release_steps: -> (build) { build.release_steps? }
}.freeze }.freeze
DEFAULT_RETRIES = { DEFAULT_RETRIES = {
...@@ -815,6 +816,7 @@ module Ci ...@@ -815,6 +816,7 @@ module Ci
def steps def steps
[Gitlab::Ci::Build::Step.from_commands(self), [Gitlab::Ci::Build::Step.from_commands(self),
Gitlab::Ci::Build::Step.from_release(self),
Gitlab::Ci::Build::Step.from_after_script(self)].compact Gitlab::Ci::Build::Step.from_after_script(self)].compact
end end
...@@ -878,6 +880,16 @@ module Ci ...@@ -878,6 +880,16 @@ module Ci
options&.dig(:artifacts, :reports)&.any? options&.dig(:artifacts, :reports)&.any?
end end
def supports_artifacts_exclude?
options&.dig(:artifacts, :exclude)&.any? &&
Gitlab::Ci::Features.artifacts_exclude_enabled?
end
def release_steps?
options.dig(:release)&.any? &&
Gitlab::Ci::Features.release_generation_enabled?
end
def hide_secrets(trace) def hide_secrets(trace)
return unless trace return unless trace
...@@ -951,11 +963,6 @@ module Ci ...@@ -951,11 +963,6 @@ module Ci
failure_reason: :data_integrity_failure) failure_reason: :data_integrity_failure)
end end
def supports_artifacts_exclude?
options&.dig(:artifacts, :exclude)&.any? &&
Gitlab::Ci::Features.artifacts_exclude_enabled?
end
def degradation_threshold def degradation_threshold
var = yaml_variables.find { |v| v[:key] == DEGRADATION_THRESHOLD_VARIABLE_NAME } var = yaml_variables.find { |v| v[:key] == DEGRADATION_THRESHOLD_VARIABLE_NAME }
var[:value]&.to_i if var var[:value]&.to_i if var
......
...@@ -20,6 +20,19 @@ module Gitlab ...@@ -20,6 +20,19 @@ module Gitlab
end end
end end
def from_release(job)
return unless Gitlab::Ci::Features.release_generation_enabled?
release = job.options[:release]
return unless release
self.new(:release).tap do |step|
step.script = Gitlab::Ci::Build::Releaser.new(config: job.options[:release]).script
step.timeout = job.metadata_timeout
step.when = WHEN_ON_SUCCESS
end
end
def from_after_script(job) def from_after_script(job)
after_script = job.options[:after_script] after_script = job.options[:after_script]
return unless after_script return unless after_script
......
...@@ -28,7 +28,7 @@ module Gitlab ...@@ -28,7 +28,7 @@ module Gitlab
in: %i[release], in: %i[release],
message: 'release features are not enabled' message: 'release features are not enabled'
}, },
unless: -> { Feature.enabled?(:ci_release_generation, default_enabled: false) } unless: -> { Gitlab::Ci::Features.release_generation_enabled? }
with_options allow_nil: true do with_options allow_nil: true do
validates :allow_failure, boolean: true validates :allow_failure, boolean: true
......
...@@ -37,6 +37,10 @@ module Gitlab ...@@ -37,6 +37,10 @@ module Gitlab
def self.atomic_processing?(project) def self.atomic_processing?(project)
::Feature.enabled?(:ci_atomic_processing, project, default_enabled: true) ::Feature.enabled?(:ci_atomic_processing, project, default_enabled: true)
end end
def self.release_generation_enabled?
::Feature.enabled?(:ci_release_generation)
end
end end
end end
end end
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
module Gitlab module Gitlab
module Ci module Ci
module Status module Status
# Base abstract class fore core status # Base abstract class for core status
# #
class Core class Core
include Gitlab::Routing include Gitlab::Routing
......
...@@ -88,7 +88,7 @@ module Gitlab ...@@ -88,7 +88,7 @@ module Gitlab
end end
def release(job) def release(job)
job[:release] if Feature.enabled?(:ci_release_generation, default_enabled: false) job[:release] if Gitlab::Ci::Features.release_generation_enabled?
end end
def stage_builds_attributes(stage) def stage_builds_attributes(stage)
......
...@@ -378,6 +378,21 @@ FactoryBot.define do ...@@ -378,6 +378,21 @@ FactoryBot.define do
end end
end end
trait :release_options do
options do
{
only: 'tags',
script: ['make changelog | tee release_changelog.txt'],
release: {
name: 'Release $CI_COMMIT_SHA',
description: 'Created using the release-cli $EXTRA_DESCRIPTION',
tag_name: 'release-$CI_COMMIT_SHA',
ref: '$CI_COMMIT_SHA'
}
}
end
end
trait :no_options do trait :no_options do
options { {} } options { {} }
end end
......
...@@ -51,6 +51,30 @@ describe Gitlab::Ci::Build::Step do ...@@ -51,6 +51,30 @@ describe Gitlab::Ci::Build::Step do
end end
end end
describe '#from_release' do
subject { described_class.from_release(job) }
before do
job.run!
end
context 'with release' do
let(:job) { create(:ci_build, :release_options) }
it 'returns the release-cli command line' do
expect(subject.script).to eq("release-cli create --name \"Release $CI_COMMIT_SHA\" --description \"Created using the release-cli $EXTRA_DESCRIPTION\" --tag-name \"release-$CI_COMMIT_SHA\" --ref \"$CI_COMMIT_SHA\"")
end
end
context 'when release is empty' do
let(:job) { create(:ci_build) }
it 'does not fabricate an object' do
is_expected.to be_nil
end
end
end
describe '#from_after_script' do describe '#from_after_script' do
let(:job) { create(:ci_build) } let(:job) { create(:ci_build) }
...@@ -61,7 +85,7 @@ describe Gitlab::Ci::Build::Step do ...@@ -61,7 +85,7 @@ describe Gitlab::Ci::Build::Step do
end end
context 'when after_script is empty' do context 'when after_script is empty' do
it 'doesn not fabricate an object' do it 'does not fabricate an object' do
is_expected.to be_nil is_expected.to be_nil
end end
end end
......
...@@ -4216,7 +4216,7 @@ describe Ci::Build do ...@@ -4216,7 +4216,7 @@ describe Ci::Build do
subject { build.supported_runner?(runner_features) } subject { build.supported_runner?(runner_features) }
context 'when feature is required by build' do context 'when `upload_multiple_artifacts` feature is required by build' do
before do before do
expect(build).to receive(:runner_required_feature_names) do expect(build).to receive(:runner_required_feature_names) do
[:upload_multiple_artifacts] [:upload_multiple_artifacts]
...@@ -4240,7 +4240,7 @@ describe Ci::Build do ...@@ -4240,7 +4240,7 @@ describe Ci::Build do
end end
end end
context 'when refspecs feature is required by build' do context 'when `refspecs` feature is required by build' do
before do before do
allow(build).to receive(:merge_request_ref?) { true } allow(build).to receive(:merge_request_ref?) { true }
end end
...@@ -4257,6 +4257,26 @@ describe Ci::Build do ...@@ -4257,6 +4257,26 @@ describe Ci::Build do
it { is_expected.to be_falsey } it { is_expected.to be_falsey }
end end
end end
context 'when `release_steps` feature is required by build' do
before do
expect(build).to receive(:runner_required_feature_names) do
[:release_steps]
end
end
context 'when runner provides given feature' do
let(:runner_features) { { release_steps: true } }
it { is_expected.to be_truthy }
end
context 'when runner does not provide given feature' do
let(:runner_features) { {} }
it { is_expected.to be_falsey }
end
end
end end
describe '#deployment_status' do describe '#deployment_status' do
......
...@@ -648,6 +648,44 @@ describe API::Runner, :clean_gitlab_redis_shared_state do ...@@ -648,6 +648,44 @@ describe API::Runner, :clean_gitlab_redis_shared_state do
end end
end end
context 'when job is for a release' do
let!(:job) { create(:ci_build, :release_options, pipeline: pipeline) }
context 'when `release_steps` is passed by the runner' do
it 'exposes release info' do
request_job info: { features: { release_steps: true } }
expect(response).to have_gitlab_http_status(:created)
expect(response.headers).not_to have_key('X-GitLab-Last-Update')
expect(json_response['steps']).to eq([
{
"name" => "script",
"script" => ["make changelog | tee release_changelog.txt"],
"timeout" => 3600,
"when" => "on_success",
"allow_failure" => false
},
{
"name" => "release",
"script" =>
"release-cli create --ref \"$CI_COMMIT_SHA\" --name \"Release $CI_COMMIT_SHA\" --tag-name \"release-$CI_COMMIT_SHA\" --description \"Created using the release-cli $EXTRA_DESCRIPTION\"",
"timeout" => 3600,
"when" => "on_success",
"allow_failure" => false
}
])
end
end
context 'when `release_steps` is not passed by the runner' do
it 'drops the job' do
request_job
expect(response).to have_gitlab_http_status(:no_content)
end
end
end
context 'when job is made for merge request' do context 'when job is made for merge request' do
let(:pipeline) { create(:ci_pipeline, source: :merge_request_event, project: project, ref: 'feature', merge_request: merge_request) } let(:pipeline) { create(:ci_pipeline, source: :merge_request_event, project: project, ref: 'feature', merge_request: merge_request) }
let!(:job) { create(:ci_build, pipeline: pipeline, name: 'spinach', ref: 'feature', stage: 'test', stage_idx: 0) } let!(:job) { create(:ci_build, pipeline: pipeline, name: 'spinach', ref: 'feature', stage: 'test', stage_idx: 0) }
......
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