Last active
June 9, 2017 08:20
-
-
Save jhass/6aae5eebe2a7b0601a8f60ef28995482 to your computer and use it in GitHub Desktop.
Update all connected devices and running emulators with the latest version of your app(s) from HockeyApp (install Ruby & bundler first)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/ruby | |
require "bundler/inline" | |
gemfile(ARGV.any? {|arg| arg == "--install"}) do | |
source "https://rubygems.org" | |
gem "http", "~> 2.2" | |
gem "ADB", "~> 0.5.6" | |
gem "slop", "~> 4.5" | |
end | |
module ADB | |
extend self | |
end | |
module HockeyApp | |
API_BASE = "https://rink.hockeyapp.net/api/2/" | |
API_TOKEN = ENV["HOCKEYAPP_API_TOKEN"] | |
module_function | |
def apps | |
get("apps")["apps"] | |
.select {|app| app["platform"] == "Android" } | |
.map {|app| App.new app } | |
end | |
def versions(app) | |
get("apps/#{app.app_id}/app_versions?include_build_urls=true")["app_versions"] | |
.select {|version| version["build_url"] } | |
.map {|version| Version.new app, version } | |
end | |
def get(endpoint) | |
HTTP.follow.headers("X-HockeyAppToken" => API_TOKEN).get(URI.join(API_BASE, endpoint)).parse | |
end | |
def download(url, local_path) | |
File.open(local_path, "w") do |file| | |
HTTP.follow.headers("X-HockeyAppToken" => API_TOKEN).get(url).body.each do |chunk| | |
file.write chunk | |
end | |
end | |
end | |
end | |
class App | |
attr_reader :app_id, :package | |
def self.all | |
HockeyApp.apps | |
end | |
def initialize(data) | |
@app_id = data["public_identifier"] | |
@package = data["bundle_identifier"] | |
end | |
def latest_version | |
versions.sort_by(&:code).last | |
end | |
def find_version(code) | |
version = versions.find {|version| version.code == code } | |
abort "#{@package} has no version #{code}" unless version | |
version | |
end | |
def versions | |
versions = HockeyApp.versions(self) | |
abort "No versions for #{@package}!" if versions.empty? | |
versions | |
end | |
end | |
class Version | |
attr_reader :app, :code | |
def initialize(app, data) | |
@app = app | |
@code = data["version"] | |
@download_url = data["build_url"] | |
end | |
def download_to(path) | |
local_path = File.join(path, "#{@app.package}-#{@code}.apk") | |
HockeyApp.download(@download_url, local_path) | |
local_path | |
end | |
end | |
class Device | |
attr_reader :serial | |
def self.all | |
ADB.devices.map {|serial| new serial } | |
end | |
def initialize(serial) | |
@serial = serial | |
end | |
def install(local_path) | |
ADB.install local_path, nil, serial: @serial | |
end | |
def uninstall(package) | |
ADB.uninstall package, serial: @serial | |
end | |
end | |
abort "Please set HOCKEYAPP_API_TOKEN" if HockeyApp::API_TOKEN.nil? || HockeyApp::API_TOKEN.empty? | |
opts = Slop.parse do |o| | |
o.bool "--install", "Install script dependencies" | |
o.array "-d", "--devices", "Limit actions to given devices instead of all" | |
o.array "-p", "--packages", "Limit actions to given apps (given by their package names)" | |
o.string "-v", "--version", "Install specific version instead of latest" | |
o.on "--help" do | |
puts o | |
exit | |
end | |
end | |
puts "Fetching devices" | |
devices = Device.all | |
abort "No devices connected!" if devices.empty? | |
unless opts[:devices].empty? | |
opts[:devices].each do |serial| | |
abort "Device #{serial} not connected!" if devices.none? {|device| device.serial == serial } | |
end | |
devices.select! {|device| opts[:device].include? device.serial } | |
end | |
puts "Fetching apps" | |
apps = App.all | |
abort "No apps configured in your HockeyApp account!" if apps.empty? | |
unless opts[:packages].empty? | |
opts[:packages].each do |package| | |
abort "App #{package} not found in HockeyApp!" if apps.none? {|app| app.package == package } | |
end | |
apps.select! {|app| opts[:packages].include? app.package } | |
end | |
puts "Fetching app versions" | |
if opts[:version] | |
versions = apps.map {|app| app.find_version(opts[:version]) } | |
else | |
versions = apps.map(&:latest_version) | |
end | |
Dir.mktmpdir do |download_folder| | |
versions.each do |version| | |
puts "Downloading #{version.app.package} #{version.code}" | |
local_path = version.download_to download_folder | |
devices.each do |device| | |
puts "Installing #{version.app.package} #{version.code} to #{device.serial}" | |
begin | |
device.install local_path | |
rescue ADB::ADBError => e # Failed retry with trying to uninstall first | |
begin | |
device.uninstall version.app.package | |
device.install local_path | |
rescue ADB::ADBError | |
raise e | |
end | |
end | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment