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