Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/Java/Openclaw/apps/ios/fastlane/   (KI Agentensystem Version 22©)  Datei vom 26.3.2026 mit Größe 10 kB image not shown  

Quelle  Fastfile

  Sprache: JAVA
 

Spracherkennung für: vermutete Sprache: Unknown {[0] [0] [0]} [Methode: Schwerpunktbildung, einfache Gewichte, sechs Dimensionen]

require "shellwords"
require "open3"
require "json"

default_platform(:ios)

BETA_APP_IDENTIFIER = "ai.openclaw.client"

def load_env_file(path)
  return unless File.exist?(path)

  File.foreach(path) do |line|
    stripped = line.strip
    next if stripped.empty? || stripped.start_with?("#")

    key, value = stripped.split("=", 2)
    next if key.nil? || key.empty? || value.nil?

    ENV[key] = value if ENV[key].nil? || ENV[key].strip.empty?
  end
end

def env_present?(value)
  !value.nil? && !value.strip.empty?
end

def clear_empty_env_var(key)
  return unless ENV.key?(key)
  ENV.delete(key) unless env_present?(ENV[key])
end

def maybe_decode_hex_keychain_secret(value)
  return value unless env_present?(value)

  candidate = value.strip
  return candidate unless candidate.match?(/\A[0-9a-fA-F]+\z/) && candidate.length.even?

  begin
    decoded = [candidate].pack("H*")
    return candidate unless decoded.valid_encoding?

    # `security find-generic-password -w` can return hex when the stored secret
    # includes newlines/non-printable bytes (like PEM files).
    beginPemMarker = %w[BEGIN PRIVATE KEY].join(" ") # pragma: allowlist secret
    endPemMarker = %w[END PRIVATE KEY].join(" ")
    if decoded.include?(beginPemMarker) || decoded.include?(endPemMarker)
      UI.message("Decoded hex-encoded ASC key content from Keychain.")
      return decoded
    end
  rescue StandardError
    return candidate
  end

  candidate
end

def read_asc_key_content_from_keychain
  service = ENV["ASC_KEYCHAIN_SERVICE"]
  service = "openclaw-asc-key" unless env_present?(service)

  account = ENV["ASC_KEYCHAIN_ACCOUNT"]
  account = ENV["USER"] unless env_present?(account)
  account = ENV["LOGNAME"] unless env_present?(account)
  return nil unless env_present?(account)

  begin
    stdout, _stderr, status = Open3.capture3(
      "security",
      "find-generic-password",
      "-s",
      service,
      "-a",
      account,
      "-w"
    )

    return nil unless status.success?

    key_content = stdout.to_s.strip
    key_content = maybe_decode_hex_keychain_secret(key_content)
    return nil unless env_present?(key_content)

    UI.message("Loaded ASC key content from Keychain service '#{service}' (account '#{account}').")
    key_content
  rescue Errno::ENOENT
    nil
  end
end

def repo_root
  File.expand_path("../../..", __dir__)
end

def ios_root
  File.expand_path("..", __dir__)
end

def read_ios_version_metadata
  script_path = File.join(repo_root, "scripts", "ios-version.ts")
  stdout, stderr, status = Open3.capture3(
    "node",
    "--import",
    "tsx",
    script_path,
    "--json",
    chdir: repo_root
  )

  unless status.success?
    detail = stderr.to_s.strip
    detail = stdout.to_s.strip if detail.empty?
    UI.user_error!("Failed to read iOS version metadata: #{detail}")
  end

  parsed = JSON.parse(stdout)
  version = parsed["canonicalVersion"].to_s.strip
  short_version = parsed["marketingVersion"].to_s.strip
  if !env_present?(version) || !env_present?(short_version)
    UI.user_error!("iOS version helper returned incomplete metadata.")
  end

  {
    short_version: short_version,
    version: version
  }
rescue JSON::ParserError => e
  UI.user_error!("Invalid JSON from iOS version helper: #{e.message}")
end

def sync_ios_versioning!
  script_path = File.join(repo_root, "scripts", "ios-sync-versioning.ts")
  stdout, stderr, status = Open3.capture3(
    "node",
    "--import",
    "tsx",
    script_path,
    "--check",
    chdir: repo_root
  )
  return if status.success?

  detail = stderr.to_s.strip
  detail = stdout.to_s.strip if detail.empty?
  UI.user_error!("iOS versioning artifacts are stale. Run `pnpm ios:version:sync`.\n#{detail}")
end

def shell_join(parts)
  Shellwords.join(parts.compact)
end

def resolve_beta_build_number(api_key:, short_version:)
  explicit = ENV["IOS_BETA_BUILD_NUMBER"]
  if env_present?(explicit)
    UI.user_error!("Invalid IOS_BETA_BUILD_NUMBER '#{explicit}'. Expected digits only.") unless explicit.match?(/\A\d+\z/)
    UI.message("Using explicit iOS beta build number #{explicit}.")
    return explicit
  end

  latest_build = latest_testflight_build_number(
    api_key: api_key,
    app_identifier: BETA_APP_IDENTIFIER,
    version: short_version,
    initial_build_number: 0
  )
  next_build = latest_build.to_i + 1
  UI.message("Resolved iOS beta build number #{next_build} for #{short_version} (latest TestFlight build: #{latest_build}).")
  next_build.to_s
end

def beta_build_number_needs_asc_auth?
  explicit = ENV["IOS_BETA_BUILD_NUMBER"]
  !env_present?(explicit)
end

def prepare_beta_release!(version:, build_number:)
  script_path = File.join(repo_root, "scripts", "ios-beta-prepare.sh")
  UI.message("Preparing iOS beta release #{version} (build #{build_number}).")
  sh(shell_join(["bash", script_path, "--build-number", build_number]))

  beta_xcconfig = File.join(ios_root, "build", "BetaRelease.xcconfig")
  UI.user_error!("Missing beta xcconfig at #{beta_xcconfig}.") unless File.exist?(beta_xcconfig)

  ENV["XCODE_XCCONFIG_FILE"] = beta_xcconfig
  beta_xcconfig
end

def build_beta_release(context)
  version = context[:version]
  output_directory = File.join("build", "beta")
  archive_path = File.join(output_directory, "OpenClaw-#{version}.xcarchive")

  build_app(
    project: "OpenClaw.xcodeproj",
    scheme: "OpenClaw",
    configuration: "Release",
    export_method: "app-store",
    clean: true,
    skip_profile_detection: true,
    build_path: "build",
    archive_path: archive_path,
    output_directory: output_directory,
    output_name: "OpenClaw-#{version}.ipa",
    xcargs: "-allowProvisioningUpdates",
    export_xcargs: "-allowProvisioningUpdates",
    export_options: {
      signingStyle: "automatic"
    }
  )

  {
    archive_path: archive_path,
    build_number: context[:build_number],
    ipa_path: lane_context[SharedValues::IPA_OUTPUT_PATH],
    short_version: context[:short_version],
    version: version
  }
end

platform :ios do
  private_lane :asc_api_key do
    load_env_file(File.join(__dir__, ".env"))
    clear_empty_env_var("APP_STORE_CONNECT_API_KEY_PATH")
    clear_empty_env_var("ASC_KEY_PATH")
    clear_empty_env_var("ASC_KEY_CONTENT")

    api_key = nil

    key_path = ENV["APP_STORE_CONNECT_API_KEY_PATH"]
    if env_present?(key_path)
      api_key = app_store_connect_api_key(path: key_path)
    else
      p8_path = ENV["ASC_KEY_PATH"]
      if env_present?(p8_path)
        key_id = ENV["ASC_KEY_ID"]
        issuer_id = ENV["ASC_ISSUER_ID"]
        UI.user_error!("Missing ASC_KEY_ID or ASC_ISSUER_ID for ASC_KEY_PATH auth.") if [key_id, issuer_id].any? { |v| !env_present?(v) }

        api_key = app_store_connect_api_key(
          key_id: key_id,
          issuer_id: issuer_id,
          key_filepath: p8_path
        )
      else
        key_id = ENV["ASC_KEY_ID"]
        issuer_id = ENV["ASC_ISSUER_ID"]
        key_content = ENV["ASC_KEY_CONTENT"]
        key_content = read_asc_key_content_from_keychain unless env_present?(key_content)

        UI.user_error!(
          "Missing App Store Connect API key. Set APP_STORE_CONNECT_API_KEY_PATH (json), ASC_KEY_PATH (p8), or ASC_KEY_ID/ASC_ISSUER_ID with ASC_KEY_CONTENT (or Keychain via ASC_KEYCHAIN_SERVICE/ASC_KEYCHAIN_ACCOUNT)."
        ) if [key_id, issuer_id, key_content].any? { |v| !env_present?(v) }

        is_base64 = key_content.include?("BEGIN PRIVATE KEY") ? false : true

        api_key = app_store_connect_api_key(
          key_id: key_id,
          issuer_id: issuer_id,
          key_content: key_content,
          is_key_content_base64: is_base64
        )
      end
    end

    api_key
  end

  private_lane :prepare_beta_context do |options|
    require_api_key = options[:require_api_key] == true
    needs_api_key = require_api_key || beta_build_number_needs_asc_auth?
    api_key = needs_api_key ? asc_api_key : nil
    sync_ios_versioning!
    version_metadata = read_ios_version_metadata
    version = version_metadata[:version]
    short_version = version_metadata[:short_version]
    build_number = resolve_beta_build_number(api_key: api_key, short_version: short_version)
    beta_xcconfig = prepare_beta_release!(version: version, build_number: build_number)

    {
      api_key: api_key,
      beta_xcconfig: beta_xcconfig,
      build_number: build_number,
      short_version: short_version,
      version: version
    }
  end

  desc "Build a beta archive locally without uploading"
  lane :beta_archive do
    context = prepare_beta_context(require_api_key: false)
    build = build_beta_release(context)
    UI.success("Built iOS beta archive: version=#{build[:version]} short=#{build[:short_version]} build=#{build[:build_number]}")
    build
  ensure
    ENV.delete("XCODE_XCCONFIG_FILE")
  end

  desc "Build + upload a beta to TestFlight"
  lane :beta do
    context = prepare_beta_context(require_api_key: true)
    build = build_beta_release(context)

    upload_to_testflight(
      api_key: context[:api_key],
      ipa: build[:ipa_path],
      skip_waiting_for_build_processing: true,
      uses_non_exempt_encryption: false
    )

    UI.success("Uploaded iOS beta: version=#{build[:version]} short=#{build[:short_version]} build=#{build[:build_number]}")
  ensure
    ENV.delete("XCODE_XCCONFIG_FILE")
  end

  desc "Upload App Store metadata (and optionally screenshots)"
  lane :metadata do
    sync_ios_versioning!
    api_key = asc_api_key
    clear_empty_env_var("APP_STORE_CONNECT_API_KEY_PATH")
    app_identifier = ENV["ASC_APP_IDENTIFIER"]
    app_id = ENV["ASC_APP_ID"]
    app_identifier = nil unless env_present?(app_identifier)
    app_id = nil unless env_present?(app_id)

    deliver_options = {
      api_key: api_key,
      force: true,
      skip_screenshots: ENV["DELIVER_SCREENSHOTS"] != "1",
      skip_metadata: ENV["DELIVER_METADATA"] != "1",
      run_precheck_before_submit: false
    }
    deliver_options[:app_identifier] = app_identifier if app_identifier
    if app_id && app_identifier.nil?
      # `deliver` prefers app_identifier from Appfile unless explicitly blanked.
      deliver_options[:app_identifier] = ""
      deliver_options[:app] = app_id
    end

    deliver(**deliver_options)
  end

  desc "Validate App Store Connect API auth"
  lane :auth_check do
    asc_api_key
    UI.success("App Store Connect API auth loaded successfully.")
  end
end

¤ Dauer der Verarbeitung: 0.47 Sekunden  (vorverarbeitet am  2026-04-27) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.