Class: Everywhere::Commands::PlatformRunner

Inherits:
Dry::CLI::Command
  • Object
show all
Defined in:
lib/everywhere/commands/platform/runner.rb

Overview

every platform runner — runs ON a build runner: a macOS machine for the macos/ios targets, macOS or Linux for android. It's the glue between the Runner API and the every release signing engine:

job spec → mark running → download+extract snapshot → pull JIT creds into
a throwaway keychain (+ .p8) → every release (streaming logs) → upload the
artifact + release.json → complete.

Authenticated with the per-artifact runner token, so it can only touch the one artifact it was dispatched for.

Constant Summary collapse

ARTIFACTS =

What every release leaves in dist/ per os, newest first when several match, and how the blob store should label it.

{ "macos" => %w[*.zip], "ios" => %w[*.ipa], "android" => %w[*.aab *.apk] }.freeze
CONTENT_TYPES =
{
  ".zip" => "application/zip",
  ".ipa" => "application/octet-stream",
  ".apk" => "application/vnd.android.package-archive",
  ".aab" => "application/octet-stream"
}.freeze
RELEASE_NARRATION =
{
  "macos"   => "every release — press → sign → notarize → staple",
  "ios"     => "every release — build → archive → export .ipa",
  "android" => "every release — assemble → sign → bundle"
}.freeze
PROFILE_DIRS =

A .mobileprovision has to be in both: Xcode reads the UserData copy, xcodebuild's own resolution still reads the MobileDevice one.

[
  "~/Library/MobileDevice/Provisioning Profiles",
  "~/Library/Developer/Xcode/UserData/Provisioning Profiles"
].freeze
PROFILE_UUID =
/\A[0-9a-f-]+\z/i

Instance Method Summary collapse

Instance Method Details

#call(artifact:, token:, url: nil, shell_dir: nil) ⇒ Object



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
# File 'lib/everywhere/commands/platform/runner.rb', line 62

def call(artifact:, token:, url: nil, shell_dir: nil, **)
  # We run headless on a build runner (a pipe, not a TTY) and stream into
  # the Platform web log, which renders ANSI. Force color on so the hosted
  # log reads like a local run.
  ENV["CLICOLOR_FORCE"] ||= "1" unless ENV["NO_COLOR"]

  base = Everywhere::Platform::Client.base_url(url)
  @client = Everywhere::Platform::Client.new(base, token: token)
  @artifact = artifact

  job = get!("/runner/artifacts/#{artifact}")
  patch!("/runner/artifacts/#{artifact}", status: "running")
  remote_log("picked up #{UI.cyan("#{UI.os_label(job.dig("target", "os"))}-#{job.dig("target", "arch")}")} for #{UI.bold(job.dig("app", "name"))}")

  Dir.mktmpdir("every-runner") do |work|
    src = fetch_snapshot(work, job)
    signing_env = pull_credentials(work)

    status, release_json, built = run_release(src, job, signing_env, shell_dir)

    if status == "succeeded" && built
      complete_success(built, release_json)
    else
      complete_failure("build failed — see log")
    end
  ensure
    restore_keychains
  end
rescue Everywhere::Error => e
  complete_failure(e.message)
  UI.die!(e.message)
rescue Everywhere::Fatal => e
  # UI.die! raises Fatal (a SystemExit), which the rescue above can't see —
  # without this an upload/signing failure would leave the artifact stuck
  # "running" on the Platform forever.
  complete_failure(e.message.to_s.empty? ? "build failed" : e.message)
  raise
end