gitlab-ce/lib/gitlab/ci/build/releaser.rb

221 lines
8.7 KiB
Ruby

# frozen_string_literal: true
module Gitlab
module Ci
module Build
class Releaser
include ::Gitlab::Utils::StrongMemoize
RELEASE_CLI_CREATE_BASE_COMMAND = 'release-cli create'
RELEASE_CLI_CREATE_SINGLE_FLAGS = %i[name description tag_name tag_message ref released_at].freeze
RELEASE_CLI_CREATE_ARRAY_FLAGS = %i[milestones].freeze
RELEASE_CLI_CATALOG_PUBLISH_FLAG = '--catalog-publish'
# If these versions or error messages are updated, the documentation should be updated as well.
TROUBLESHOOTING_URL = Rails.application.routes.url_helpers.help_page_url('user/project/releases/_index.md', anchor: 'gitlab-cli-version-requirement')
GLAB_REQUIRED_VERSION = '1.58.0'
GLAB_WARNING_MESSAGE = "Warning: release-cli will not be supported after 19.0. Please use glab version >= #{GLAB_REQUIRED_VERSION}. Troubleshooting: #{TROUBLESHOOTING_URL}".freeze
GLAB_ENV_SET_UNIX = 'export GITLAB_HOST=$CI_SERVER_URL'
GLAB_ENV_SET_WINDOWS = '$$env:GITLAB_HOST = $$env:CI_SERVER_URL'
GLAB_LOGIN_UNIX = 'glab auth login --job-token $CI_JOB_TOKEN --hostname "$CI_SERVER_FQDN" --api-protocol $CI_SERVER_PROTOCOL'
GLAB_LOGIN_WINDOWS = 'glab auth login --job-token $$env:CI_JOB_TOKEN --hostname "$$env:CI_SERVER_FQDN" --api-protocol $$env:CI_SERVER_PROTOCOL'
GLAB_CREATE_UNIX = 'glab release create -R $CI_PROJECT_PATH'
GLAB_CREATE_WINDOWS = 'glab release create -R $$env:CI_PROJECT_PATH'
GLAB_PUBLISH_TO_CATALOG_FLAG = '--publish-to-catalog' # enables publishing to the catalog after creating the release
GLAB_NO_UPDATE_FLAG = '--no-update' # disables updating the release if it already exists
GLAB_NO_CLOSE_MILESTONE_FLAG = '--no-close-milestone' # disables closing the milestone after creating the release
GLAB_CA_CERT_FILENAME = 'ca_cert_for_releasing_with_glab.pem'
GLAB_CA_CERT_CONFIG_UNIX = <<~BASH.chomp.freeze
if [ -n "$ADDITIONAL_CA_CERT_BUNDLE" ]; then
echo "Setting CA certificate for $CI_SERVER_FQDN"
echo "$ADDITIONAL_CA_CERT_BUNDLE" > "#{GLAB_CA_CERT_FILENAME}"
glab config set ca_cert "#{GLAB_CA_CERT_FILENAME}" --host "$CI_SERVER_FQDN"
fi
BASH
GLAB_CA_CERT_CLEANUP_UNIX = <<~BASH.chomp.freeze
if [ -f "#{GLAB_CA_CERT_FILENAME}" ]; then
rm -f "#{GLAB_CA_CERT_FILENAME}"
fi
BASH
GLAB_CA_CERT_CONFIG_WINDOWS = <<~POWERSHELL.chomp.freeze
if ($$env:ADDITIONAL_CA_CERT_BUNDLE) {
Write-Output "Setting CA certificate for $$env:CI_SERVER_FQDN"
"$$env:ADDITIONAL_CA_CERT_BUNDLE" > "#{GLAB_CA_CERT_FILENAME}"
glab config set ca_cert "#{GLAB_CA_CERT_FILENAME}" --host "$$env:CI_SERVER_FQDN"
}
POWERSHELL
GLAB_CA_CERT_CLEANUP_WINDOWS = <<~POWERSHELL.chomp.freeze
if (Test-Path "#{GLAB_CA_CERT_FILENAME}") {
Remove-Item -Force "#{GLAB_CA_CERT_FILENAME}"
}
POWERSHELL
attr_reader :job, :config, :runner_manager
def initialize(job:)
@job = job
@config = job.options[:release]
@runner_manager = job.runner_manager
Gitlab::AppJsonLogger.info(
class: self.class.to_s,
message: 'The release script for the release build is being prepared.',
runner_id: job.runner&.id,
runner_type: job.runner&.runner_type,
runner_platform: job.runner_manager&.platform
)
end
def script
if use_glab_cli?
[script_with_glab_cli]
else
[script_with_release_cli]
end
end
private
def script_with_glab_cli
if runner_manager&.platform == 'windows'
glab_windows_script
else
glab_unix_script
end
end
def glab_windows_script
<<~POWERSHELL
if (Get-Command glab -ErrorAction SilentlyContinue) {
$$glabVersionOutput = (glab --version | Select-Object -First 1) -as [string]
if ($$glabVersionOutput -match 'glab (\\\d+\\\.\\\d+\\\.\\\d+)') {
if ([version]$$matches[1] -ge [version]"#{GLAB_REQUIRED_VERSION}") {
#{GLAB_ENV_SET_WINDOWS}
#{GLAB_CA_CERT_CONFIG_WINDOWS}
#{GLAB_LOGIN_WINDOWS}
#{glab_create_command('windows')}
#{GLAB_CA_CERT_CLEANUP_WINDOWS}
}
else {
Write-Output "#{GLAB_WARNING_MESSAGE}"
#{script_with_release_cli}
}
}
else {
Write-Output "#{GLAB_WARNING_MESSAGE}"
#{script_with_release_cli}
}
}
else {
Write-Output "#{GLAB_WARNING_MESSAGE}"
#{script_with_release_cli}
}
POWERSHELL
end
def glab_unix_script
<<~BASH
if command -v glab &> /dev/null; then
if [ "$(printf "%s\\n%s" "#{GLAB_REQUIRED_VERSION}" "$(glab --version | grep -oE '[0-9]+\\.[0-9]+\\.[0-9]+')" | sort -V | head -n1)" = "#{GLAB_REQUIRED_VERSION}" ]; then
#{GLAB_ENV_SET_UNIX}
#{GLAB_CA_CERT_CONFIG_UNIX}
#{GLAB_LOGIN_UNIX}
#{glab_create_command('unix')}
#{GLAB_CA_CERT_CLEANUP_UNIX}
else
echo "#{GLAB_WARNING_MESSAGE}"
#{script_with_release_cli}
fi
else
echo "#{GLAB_WARNING_MESSAGE}"
#{script_with_release_cli}
fi
BASH
end
def script_with_release_cli
command = RELEASE_CLI_CREATE_BASE_COMMAND.dup
config.slice(*RELEASE_CLI_CREATE_SINGLE_FLAGS).each { |k, v| command.concat(" --#{k.to_s.dasherize} \"#{v}\"") }
config.slice(*RELEASE_CLI_CREATE_ARRAY_FLAGS).each { |k, v| v.each { |elem| command.concat(" --#{k.to_s.singularize.dasherize} \"#{elem}\"") } }
create_asset_links.each { |link| command.concat(" --assets-link #{stringified_json(link)}") }
if catalog_publish? && ci_release_cli_catalog_publish_option?
command.concat(" #{RELEASE_CLI_CATALOG_PUBLISH_FLAG}")
end
command.freeze
end
def glab_create_command(platform) # rubocop:disable Metrics/ -- It's more readable this way
if platform == 'windows'
command = GLAB_CREATE_WINDOWS.dup
# More information: https://gitlab.com/groups/gitlab-org/-/epics/15437#note_2432564707
tag_name = config[:tag_name].presence || '$$env:CI_COMMIT_TAG'
ref = config[:ref].presence || '$$env:CI_COMMIT_SHA'
else
command = GLAB_CREATE_UNIX.dup
# More information: https://gitlab.com/groups/gitlab-org/-/epics/15437#note_2432564707
tag_name = config[:tag_name].presence || '$CI_COMMIT_TAG'
ref = config[:ref].presence || '$CI_COMMIT_SHA'
end
command.concat(" \"#{tag_name}\"")
command.concat(" --assets-links #{stringified_json(create_asset_links)}") if create_asset_links.present?
command.concat(" --milestone \"#{config[:milestones].join(',')}\"") if config[:milestones].present?
command.concat(" --name \"#{config[:name]}\"") if config[:name].present?
if config[:description].present?
# More information: https://gitlab.com/gitlab-org/cli/-/issues/7762
command.concat(" --experimental-notes-text-or-file \"#{config[:description]}\"")
end
command.concat(" --ref \"#{ref}\"") if ref.present?
command.concat(" --tag-message \"#{config[:tag_message]}\"") if config[:tag_message].present?
command.concat(" --released-at \"#{config[:released_at]}\"") if config[:released_at].present?
command.concat(" #{GLAB_NO_UPDATE_FLAG} #{GLAB_NO_CLOSE_MILESTONE_FLAG}")
if catalog_publish? && ci_release_cli_catalog_publish_option?
command.concat(" #{GLAB_PUBLISH_TO_CATALOG_FLAG}")
end
command.freeze
end
def create_asset_links
config.dig(:assets, :links) || []
end
def stringified_json(object)
object.to_json.to_json.to_s
end
def catalog_publish?
job.project.catalog_resource
end
strong_memoize_attr :catalog_publish?
def use_glab_cli?
::Feature.enabled?(:ci_glab_for_release, job.project)
end
strong_memoize_attr :use_glab_cli?
def ci_release_cli_catalog_publish_option?
::Feature.enabled?(:ci_release_cli_catalog_publish_option, job.project)
end
strong_memoize_attr :ci_release_cli_catalog_publish_option?
end
end
end
end