Class: Homebrew::TestBot::TestFormulae Private

Inherits:
Test show all
Includes:
OS::Linux::TestBot::TestFormulae, OS::Mac::TestBot::TestFormulae
Defined in:
test_bot/test_formulae.rb

This class is part of a private API. This class may only be used in the Homebrew/brew repository. Third parties should avoid using this class if possible, as it may be removed or changed without warning.

Direct Known Subclasses

BottlesFetch, Formulae, FormulaeDependents

Instance Attribute Summary collapse

Attributes inherited from Test

#steps

Instance Method Summary collapse

Methods inherited from Test

#failed_steps, #ignored_steps, #test

Methods included from Utils::Output::Mixin

#issue_reporting_message, #odebug, #odeprecated, #odie, #odisabled, #ofail, #oh1, #oh1_title, #ohai, #ohai_title, #onoe, #opoo, #opoo_outside_github_actions, #opoo_without_github_actions_annotation, #pretty_deprecated, #pretty_disabled, #pretty_duration, #pretty_install_status, #pretty_installed, #pretty_uninstalled, #pretty_unmarked, #pretty_upgradable, #pretty_warning

Constructor Details

#initialize(tap:, git:, dry_run:, fail_fast:, verbose:) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Parameters:

  • tap (Tap, nil)
  • git (String, nil)
  • dry_run (Boolean)
  • fail_fast (Boolean)
  • verbose (Boolean)


27
28
29
30
31
32
33
34
35
36
37
# File 'test_bot/test_formulae.rb', line 27

def initialize(tap:, git:, dry_run:, fail_fast:, verbose:)
  super

  @skipped_or_failed_formulae = T.let([], T::Array[String])
  @artifact_cache = T.let(Pathname.new("artifact-cache"), Pathname)
  # Let's keep track of the artifacts we've already downloaded
  # to avoid repeatedly trying to download the same thing.
  @downloaded_artifacts = T.let(Hash.new { |h, k| h[k] = [] }, T::Hash[String, T::Array[String]])
  @testing_formulae = T.let([], T::Array[String])
  @tested_formulae = T.let([], T::Array[String])
end

Instance Attribute Details

#artifact_cachePathname (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



13
14
15
# File 'test_bot/test_formulae.rb', line 13

def artifact_cache
  @artifact_cache
end

#downloaded_artifactsHash{String => Array<String>} (readonly)

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



16
17
18
# File 'test_bot/test_formulae.rb', line 16

def downloaded_artifacts
  @downloaded_artifacts
end

#skipped_or_failed_formulaeArray<String>

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

Returns:



10
11
12
# File 'test_bot/test_formulae.rb', line 10

def skipped_or_failed_formulae
  @skipped_or_failed_formulae
end

Instance Method Details

#download_artifacts_from_previous_run!(artifact_pattern, dry_run:) ⇒ void

This method is part of a private API. This method may only be used in the Homebrew/brew repository. Third parties should avoid using this method if possible, as it may be removed or changed without warning.

This method returns an undefined value.

Parameters:

  • artifact_pattern (String)
  • dry_run (Boolean)


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
# File 'test_bot/test_formulae.rb', line 40

def download_artifacts_from_previous_run!(artifact_pattern, dry_run:)
  return if dry_run
  return if GitHub::API.credentials_type == :none
  return if (sha = previous_github_sha).blank?

  pull_number = github_event_payload&.dig("pull_request", "number")
  return if pull_number.blank?

  github_repository = ENV.fetch("GITHUB_REPOSITORY")
  owner, repo = *github_repository.split("/")
  raise "github_repository #{github_repository} is invalid" if owner.nil? || repo.nil?

  pr_labels = GitHub.pull_request_labels(owner, repo, pull_number)
  # Also disable bottle cache for PRs modifying workflows to avoid cache poisoning.
  return if pr_labels.include?("CI-no-bottle-cache") || pr_labels.include?("workflows")

  variables = {
    owner:,
    repo:,
    commit: sha,
  }

  response = GitHub::API.open_graphql(GRAPHQL_QUERY, variables:)
  check_suite_nodes = response.dig("repository", "object", "checkSuites", "nodes")
  return if check_suite_nodes.blank?

  wanted_artifacts = (check_suite_nodes, github_repository, "pull_request",
                                       "CI", "conclusion", artifact_pattern)
  wanted_artifacts_pattern = artifact_pattern
  if wanted_artifacts.empty?
    # If we didn't find the artifacts that we wanted, fall back to the `event_payload` artifact.
    wanted_artifacts = (check_suite_nodes, github_repository, "pull_request_target",
                                         "Triage tasks", "upload-metadata", "event_payload")
    wanted_artifacts_pattern = "event_payload"
  end
  return if wanted_artifacts.empty?

  if (attempted_artifact = wanted_artifacts.find do |artifact|
        # Hash value must exist due to the hash having a default value of an empty array.
        T.must(@downloaded_artifacts[sha]).include?(artifact.fetch("name"))
      end)
    opoo "Already tried #{attempted_artifact.fetch("name")} from #{sha}, giving up"
    return
  end

  cached_event_json&.unlink if File.fnmatch?(wanted_artifacts_pattern, "event_payload", File::FNM_EXTGLOB)

  require "utils/github/artifacts"

  ohai "Downloading artifacts matching pattern #{wanted_artifacts_pattern} from #{sha}"
  artifact_cache.mkpath
  artifact_cache.cd do
    wanted_artifacts.each do |artifact|
      name = artifact.fetch("name")
      ohai "Downloading artifact #{name} from #{sha}"
      # Hash value must exist due to the hash having a default value of an empty array.
      T.must(@downloaded_artifacts[sha]) << name

      download_url = artifact.fetch("archive_download_url")
      artifact_id = artifact.fetch("id")
      GitHub.download_artifact(download_url, artifact_id.to_s)
    end
  end

  return if wanted_artifacts_pattern == artifact_pattern

  # If we made it here, then we downloaded an `event_payload` artifact.
  # We can now use this `event_payload` artifact to attempt to download the artifact we wanted.
  download_artifacts_from_previous_run!(artifact_pattern, dry_run:)
rescue GitHub::API::AuthenticationFailedError => e
  opoo e
end