Class: Captive::GhCLI

Inherits:
Object
  • Object
show all
Defined in:
lib/captive/gh_cli.rb

Constant Summary collapse

PLATFORM_REPO =
"captive-studio/captive-platform"

Instance Method Summary collapse

Instance Method Details

#app_installed?(repo) ⇒ Boolean

Returns:

  • (Boolean)


48
49
50
51
52
53
# File 'lib/captive/gh_cli.rb', line 48

def app_installed?(repo)
  run("api", "repos/#{repo}/installation")
  true
rescue RuntimeError
  false
end

#detect_type(repo) ⇒ Object



55
56
57
58
59
60
61
62
# File 'lib/captive/gh_cli.rb', line 55

def detect_type(repo)
  data = JSON.parse(run("api", "repos/#{repo}"))
  case data["language"]
  when "Ruby"                     then "rails-app"
  when "JavaScript", "TypeScript" then "node-app"
  else raise UnknownAppType, "language non supportée : #{data["language"]}"
  end
end

#dispatch_build(repo) ⇒ Object



66
67
68
69
70
71
72
73
74
75
# File 'lib/captive/gh_cli.rb', line 66

def dispatch_build(repo)
  repo_name = repo.split("/").last.downcase
  sha = run("api", "repos/#{repo}/git/ref/heads/main", "--jq", ".object.sha").strip
  body = JSON.generate(
    event_type: "build-app",
    client_payload: { repo: repo, repo_name: repo_name, sha: sha, ref: "refs/heads/main" }
  )
  run_with_input("api", "repos/#{PLATFORM_REPO}/dispatches", "-X", "POST", "--input", "-",
                 input: body)
end

#image_exists?(repo, tag) ⇒ Boolean

Returns:

  • (Boolean)


38
39
40
41
42
43
44
45
46
# File 'lib/captive/gh_cli.rb', line 38

def image_exists?(repo, tag)
  output = run("api", "/repos/#{repo}/packages/container/#{repo.split("/").last}/versions",
               "--jq", ".[].metadata.container.tags[]")
  output.split("\n").include?(tag)
rescue RuntimeError => e
  return false if e.message.include?("404") || e.message.include?("Not Found")

  raise
end

#latest_run_status(repo) ⇒ Object



28
29
30
31
32
33
34
35
36
# File 'lib/captive/gh_cli.rb', line 28

def latest_run_status(repo)
  output = run("run", "list", "--repo", repo, "--limit", "1",
               "--json", "status,conclusion", "--jq", ".[0]")
  data = JSON.parse(output)
  return :success    if data["status"] == "completed" && data["conclusion"] == "success"
  return :failure    if data["status"] == "completed"

  :in_progress
end

#run(*args, input: nil) ⇒ Object



77
78
79
80
81
82
83
# File 'lib/captive/gh_cli.rb', line 77

def run(*args, input: nil)
  opts = input ? { stdin_data: input } : {}
  out, err, status = Open3.capture3("gh", *args, **opts)
  raise "gh #{args.join(" ")} failed: #{err}" unless status.success?

  out
end

#run_with_input(*args, input:) ⇒ Object



85
86
87
# File 'lib/captive/gh_cli.rb', line 85

def run_with_input(*args, input:)
  run(*args, input: input)
end

#trigger_workflow(repo, workflow: "ci.yml", ref: "main", fields: {}) ⇒ Object



9
10
11
12
13
14
15
16
17
18
# File 'lib/captive/gh_cli.rb', line 9

def trigger_workflow(repo, workflow: "ci.yml", ref: "main", fields: {})
  field_args = fields.flat_map { |k, v| [ "--field", "#{k}=#{v}" ] }
  run("workflow", "run", workflow, "--repo", repo, "--ref", ref, *field_args)
rescue RuntimeError => e
  raise WorkflowDispatchNotConfigured,
    "Le workflow '#{workflow}' de '#{repo}' n'a pas de trigger workflow_dispatch.\n" \
    "  Regénère le ci.yml : captive apps launch <app> dans le repo de l'app." \
    if e.message.include?("workflow_dispatch")
  raise
end

#workflow_exists?(repo) ⇒ Boolean

Returns:

  • (Boolean)


20
21
22
23
24
25
26
# File 'lib/captive/gh_cli.rb', line 20

def workflow_exists?(repo)
  %w[deploy.yml ci.yml].any? do |file|
    run("api", "/repos/#{repo}/contents/.github/workflows/#{file}") && true
  rescue RuntimeError
    false
  end
end