lib/release_tools/public_release/omnibus_gitlab_release.rb (220 lines of code) (raw):
# frozen_string_literal: true
module ReleaseTools
module PublicRelease
# A release of Omnibus GitLab using the API.
class OmnibusGitlabRelease
include Release
attr_reader :version, :client, :release_metadata
VERSION_FILE = 'VERSION'
VERSION_FILES = [
Project::Gitaly.version_file,
Project::GitlabPages.version_file,
Project::GitlabShell.version_file,
Project::GitlabElasticsearchIndexer.version_file,
Project::Kas.version_file
].freeze
VARIABLES_FILE = 'gitlab-ci-config/variables.yml'
# We started updating the QA ref as part of release, and thus using a
# separate variables.yml file, in GitLab 17.3.0
# https://gitlab.com/gitlab-org/omnibus-gitlab/-/merge_requests/7805
SEPARATE_VARIABLES_FILE_VERSION = '17.3.0'
PRE_INSTALL_SCRIPT = 'config/templates/package-scripts/preinst.erb'
UPGRADE_CHECK_SCRIPT = 'files/gitlab-ctl-commands/lib/gitlab_ctl/upgrade_check.rb'
def initialize(
version,
client: GitlabClient,
release_metadata: ReleaseMetadata.new,
commit: nil
)
unless version.ee?
raise ArgumentError, "#{version} is not an EE version"
end
@version = version
@gitlab_version = Version.new(version.to_normalized_version)
@client = client
@release_metadata = release_metadata
@commit = commit
end
def execute
logger.info(
'Starting release of Omnibus GitLab',
ee_version: version,
ce_version: version.to_ce
)
verify_version_file
create_target_branch
return if SharedStatus.dry_run?
compile_changelog
update_component_versions
update_last_upgrade_stop
ce_tag = create_ce_tag
ee_tag = create_ee_tag
add_release_data_for_tags(ce_tag, ee_tag)
notify_slack(project, version)
end
def verify_version_file
return if SharedStatus.dry_run?
path = ee_project_path
branch = ee_stable_branch
from_file = read_version(path, VERSION_FILE, branch)
return if @gitlab_version == from_file
raise "The VERSION file in #{path} on branch #{branch} specifies " \
"version #{from_file}, but the GitLab version we are releasing " \
"is version #{@gitlab_version}. These versions must be identical " \
"before we can proceed"
end
def compile_changelog
return if version.rc?
logger.info('Compiling changelog', project: project_path)
ChangelogCompiler
.new(project_path, client: client)
.compile(version, branch: target_branch)
end
def create_ce_tag
tag = version.to_ce.tag
logger.info('Creating CE tag', tag: tag, project: ce_project_path)
find_or_create_tag(tag, ce_project_path, ce_stable_branch)
end
def create_ee_tag
tag = tag_name
logger.info('Creating EE tag', tag: tag, project: ee_project_path)
find_or_create_tag(tag, ee_project_path, ee_stable_branch)
end
def find_or_create_tag(tag, gitlab_project, gitlab_branch)
Retriable.with_context(:api) do
client.tag(project_path, tag: tag)
rescue Gitlab::Error::NotFound
gitlab_version =
read_version(gitlab_project, VERSION_FILE, gitlab_branch)
update_variables(gitlab_project, gitlab_branch) if version >= Version.new(SEPARATE_VARIABLES_FILE_VERSION)
update_version_file(gitlab_version)
# Omnibus requires annotated tags to build packages, so we must
# specify a message.
client.create_tag(project_path, tag, target_branch, "Version #{tag}")
end
end
def update_variables(gitlab_project, gitlab_branch)
variables_yaml = read_file(VARIABLES_FILE)
variables_data = YAML.safe_load(variables_yaml)
variables_data['variables'].merge!(
'QA_TESTS_UPSTREAM_PROJECT' => gitlab_project,
'QA_TESTS_REF' => gitlab_branch
)
commit_version_files(
target_branch,
{ VARIABLES_FILE => YAML.dump(variables_data) },
message: "Set QA test targets for #{version}\n\n[ci skip]"
)
end
# Updates the contents of all component versions (e.g.
# GITALY_SERVER_VERSION) according to their contents in the GitLab EE
# repository.
def update_component_versions
logger.info(
'Updating component versions',
project: project_path,
branch: target_branch
)
branch = ee_stable_branch
versions = VERSION_FILES.each_with_object({}) do |file, hash|
hash[file] = read_version(ee_project_path, file, branch).to_s
end
commit_version_files(
target_branch,
versions,
message: 'Update component version files'
)
end
def update_version_file(version)
commit_version_files(
target_branch,
{ VERSION_FILE => version },
message: "Update #{VERSION_FILE} to #{version}"
)
end
def update_last_upgrade_stop
return if ReleaseTools::Feature.disabled?(:maintain_upgrade_stops)
begin
stop = UpgradeStop.new.last_required_stop
logger.info('Last required stop for version detected', last_required_stop: stop)
actions = []
actions << change_upgrade_stop_action!(PRE_INSTALL_SCRIPT, /(?<=[\s]|^)MIN_VERSION=[^\n]*/, "MIN_VERSION=#{stop}")
actions << change_upgrade_stop_action!(UPGRADE_CHECK_SCRIPT, /ENV\['MIN_VERSION'\] [\|]{2} '[0-9.]*'/, "ENV['MIN_VERSION'] || '#{stop}'")
actions.compact!
if actions.empty?
logger.info('Nothing to be done to apply upgrade stop to Omnibus', version: version.to_minor, last_required_stop: stop)
return
end
Retriable.with_context(:api) do
client.create_commit(
project_path,
project.default_branch,
"Update upgrade stop to #{stop}\n\n[ci skip]",
actions
)
end
rescue StandardError
logger.fatal('Something went wrong with the Omnibus upgrade stop. Disable the \'maintain_upgrade_stops\' feature flag, and retry the job. Please notify Distribution about this error.')
raise
end
end
def change_upgrade_stop_action!(filename, regexp, replacement)
content = read_file(filename, branch: project.default_branch)
raise "The regexp '#{regexp}' does not match in #{filename}" unless regexp.match?(content)
new_content = content.sub(regexp, replacement)
return nil if content == new_content
{
action: 'update',
file_path: filename,
content: new_content
}
end
def add_release_data_for_tags(ce_tag, ee_tag)
meta_version = version.to_normalized_version
logger.info(
'Recording release data',
project: project_path,
version: meta_version,
ce_tag: ce_tag.name,
ee_tag: ee_tag.name
)
release_metadata.add_release(
name: 'omnibus-gitlab-ce',
version: meta_version,
sha: ce_tag.commit.id,
ref: ce_tag.name,
tag: true
)
release_metadata.add_release(
name: 'omnibus-gitlab-ee',
version: meta_version,
sha: ee_tag.commit.id,
ref: ee_tag.name,
tag: true
)
end
def read_file(file, project: project_path, branch: target_branch)
Retriable.with_context(:api) do
client.file_contents(project, file, branch)
end
end
def read_version(project, name, branch)
Version.new(read_file(name, project: project, branch: branch))
end
def source_for_target_branch
if @commit
logger.info('Using specific commit', project: project_path, commit: @commit)
end
@commit || super
end
def project
Project::OmnibusGitlab
end
def ce_project_path
Project::GitlabCe.canonical_or_security_path
end
def ee_project_path
Project::GitlabEe.canonical_or_security_path
end
def ee_stable_branch
@gitlab_version.stable_branch(ee: true)
end
def ce_stable_branch
@gitlab_version.stable_branch
end
# release/metadata is unsuitable for tagging omnibus as it will
# always track an "update components version" commit that only
# exists on the security mirror as we don't create auto-deploy
# branches from canonical.
#
# However this is not a problem as the content of that commit
# will always be overwritten by the public release code commit
# the final versions of each components from the
# update_component_versions method.
def last_production_commit
last_production_commit_deployments
end
end
end
end