lib/release_tools/commits.rb (71 lines of code) (raw):

# frozen_string_literal: true module ReleaseTools class Commits include ::SemanticLogger::Loggable MAX_COMMITS_TO_CHECK = 100 def initialize(project, ref: project.default_branch, client: ReleaseTools::GitlabClient) @project = project @ref = ref @client = client end def merge_base(other_ref) @client.merge_base(@project.auto_deploy_path, [@ref, other_ref])&.id end # Get the latest commit for `ref` def latest commit_list.first end delegate :detect, to: :commit_list # Find a commit with a passing build on production that also exists on dev. # The definition of success changes based on the operation, a predicate block # must be provided that receives a commit id and returns if it is a success. # # @param since_last_auto_deploy [boolean] if true, it will limit the search to # the merge base with the SHA of last auto_deploy package # @yieldparam commit_id [string] The commit ID to validate for success # @yieldreturn [boolean] whatever the provided commit should be considered successful def latest_successful_on_build(since_last_auto_deploy: true) limit = find_last_auto_deploy_limit_sha if since_last_auto_deploy commit_list.detect do |commit| if commit.id == limit logger.info('Reached the limit commit', project: @project.auto_deploy_path, limit: limit) next true end next unless yield(commit.id) begin # Hit the dev API with the specified commit to see if it even exists Retriable.with_context(:mirroring) do ReleaseTools::GitlabDevClient .commit(@project.dev_path, ref: commit.id) end logger.info( 'Passing commit found on Build', project: @project.auto_deploy_path, commit: commit.id ) rescue Gitlab::Error::Error logger.debug( 'Commit passed on Canonical, missing on Build', project: @project.auto_deploy_path, commit: commit.id ) false end end end # @param commit_id [String] is a commit in the commit_list. # @return [ObjectifiedHash, nil] Returns the next chronologically newer commit after commit_id. # Returns nil if commit_id doesn't exist in commit_list, or if there is no # commit newer than commit_id. def next_commit(commit_id) index = commit_list.index { |c| c.id == commit_id } return if index.nil? || index.zero? # Since the commit_list is in descending chronological order, the previous commit # in the list is the next newer commit. commit_list[index - 1] end def find_last_auto_deploy_limit_sha # Helm auto-deploy support is incomplete and we are not tracking it return unless [Project::GitlabEe, Project::OmnibusGitlab, Project::CNGImage].include?(@project) return @find_last_auto_deploy_limit_sha if defined?(@find_last_auto_deploy_limit_sha) product_version = ProductVersion.last_auto_deploy last_pkg_sha = product_version[@project.metadata_project_name]&.sha logger.info('Finding auto_deploy limit SHA', project: @project, last_product_version: product_version.version, last_pkg_sha: last_pkg_sha) # TODO (rpereira2): Raise an error here instead of silently returning nil? return unless last_pkg_sha @find_last_auto_deploy_limit_sha = merge_base(last_pkg_sha).tap do |id| logger.info('Found auto_deploy limit SHA', limit_sha: id) end end private def commit_list @commit_list ||= @client.commits( @project.auto_deploy_path, per_page: MAX_COMMITS_TO_CHECK, ref_name: @ref ) end end end