|
| 1 | +# frozen_string_literal: true |
| 2 | + |
| 3 | +require 'json' |
| 4 | +require 'time' |
| 5 | +require 'open3' |
| 6 | +require 'net/http' |
| 7 | +require 'uri' |
| 8 | +require 'shellwords' |
| 9 | + |
| 10 | +PREFIX = 'simplenote-ios' |
| 11 | + |
| 12 | +XCRESULT_PATH = ARGV[0] || 'build/results/Simplenote.xcresult' |
| 13 | + |
| 14 | +# Hardcoded auth config (or set via ENV) |
| 15 | +METRICS_URL = ENV['METRICS_URL'] || 'https://metrics.a8c-ci.services/api/grouped-metrics' |
| 16 | +TOKEN = ENV['APPS_METRICS_UPLOAD_TOKEN'] |
| 17 | + |
| 18 | +META = [ |
| 19 | + { name: 'simplenote-ios-user', value: ENV['USER'] || ENV['USERNAME'] || 'unknown' }, |
| 20 | + { name: 'simplenote-ios-project', value: 'simplenote-ios' }, |
| 21 | + { name: 'simplenote-ios-environment', value: ENV['CI'] ? 'CI' : 'LOCAL' }, |
| 22 | + { name: 'simplenote-ios-architecture', value: `uname -m`.strip }, |
| 23 | + { name: 'simplenote-ios-operating-system', value: `uname -s`.strip.downcase } |
| 24 | +].freeze |
| 25 | + |
| 26 | +# ---------- HELPERS ---------- |
| 27 | +def run_cmd!(cmd) |
| 28 | + out, err, status = Open3.capture3(cmd) |
| 29 | + raise "Command failed (#{status.exitstatus}): #{cmd}\n#{err}" unless status.success? |
| 30 | + |
| 31 | + out |
| 32 | +end |
| 33 | + |
| 34 | +def to_epoch_ms(str_time) |
| 35 | + return nil if str_time.nil? || str_time.empty? |
| 36 | + |
| 37 | + (Time.parse(str_time).to_f * 1000).to_i |
| 38 | +rescue |
| 39 | + nil |
| 40 | +end |
| 41 | + |
| 42 | +def dig_count(obj, *path) |
| 43 | + v = obj.dig(*path) |
| 44 | + return v.to_i if v.is_a?(Numeric) || v.is_a?(String) |
| 45 | + return v.length if v.is_a?(Array) |
| 46 | + |
| 47 | + 0 |
| 48 | +end |
| 49 | + |
| 50 | +raw_json = run_cmd!("xcrun xcresulttool get build-results --path #{Shellwords.escape(XCRESULT_PATH)} --format json") |
| 51 | +data = JSON.parse(raw_json) |
| 52 | + |
| 53 | +end_time = (data['endTime'] * 1_000).round(0) |
| 54 | +start_time = (data['startTime'] * 1_000).round(0) |
| 55 | + |
| 56 | +explicit_fields = { |
| 57 | + 'action-title' => data['actionTitle'], |
| 58 | + 'analyzer-warning-count' => data['analyzerWarningCount'], |
| 59 | + 'end-time-unix-ms' => end_time, |
| 60 | + 'error-count' => data['errorCount'], |
| 61 | + 'start-time-unix-ms' => start_time, |
| 62 | + 'status' => data['status'], |
| 63 | + 'warning-count' => data['warningCount'], |
| 64 | + 'build-time' => end_time - start_time |
| 65 | +} |
| 66 | + |
| 67 | +metrics_payload = explicit_fields.map do |k, v| |
| 68 | + { name: "#{PREFIX}-#{k}", value: v.to_s } |
| 69 | +end |
| 70 | + |
| 71 | +payload = { |
| 72 | + meta: META, |
| 73 | + metrics: metrics_payload |
| 74 | +} |
| 75 | + |
| 76 | +puts JSON.pretty_generate(payload) |
| 77 | + |
| 78 | +uri = URI(METRICS_URL) |
| 79 | +http = Net::HTTP.new(uri.host, uri.port) |
| 80 | +http.use_ssl = (uri.scheme == 'https') |
| 81 | + |
| 82 | +req = Net::HTTP::Post.new(uri.request_uri) |
| 83 | +req['Accept'] = 'application/json' |
| 84 | +req['Accept-Charset'] = 'UTF-8' |
| 85 | +req['Authorization'] = "Bearer #{TOKEN}" |
| 86 | +req['User-Agent'] = 'Xcode/xcresulttool' |
| 87 | +req['Content-Type'] = 'application/json' |
| 88 | +req.body = JSON.dump(payload) |
| 89 | + |
| 90 | +res = http.request(req) |
| 91 | + |
| 92 | +puts "POST #{METRICS_URL} -> #{res.code}" |
| 93 | +puts res.body |
| 94 | +exit(res.code.to_i.between?(200, 299) ? 0 : 1) |
0 commit comments