infinite-loop 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,17 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in infinite-loop.gemspec
4
+ gemspec
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Thomas Dohmke
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,79 @@
1
+ # Infinite::Loop
2
+
3
+ ### CLI for HockeyApp
4
+
5
+ List apps and devices from HockeyApp. Highly inspired by the great [Cupertino](https://github.com/mattt/cupertino).
6
+
7
+ ## Installation
8
+
9
+ ```sh
10
+ $ gem install infinite-loop
11
+ ```
12
+
13
+ ## Usage
14
+
15
+ ### Fetch or Create an API token
16
+
17
+ ```sh
18
+ $ hockey login
19
+ ```
20
+
21
+ This asks you for your email and password. It then checks if you have any existing read-only tokens and stores the first in ~/.netrc. If not, it creates one.
22
+
23
+ ### List of Apps
24
+
25
+ ```sh
26
+ $ hockey apps:list
27
+ ```
28
+
29
+ ### List of Devices
30
+
31
+ ```sh
32
+ $ hockey devices:list APP_ID
33
+ ```
34
+
35
+ If you only want devices which are not in your current provisioning profile, add "unprovisioned":
36
+
37
+ ```sh
38
+ $ hockey devices:list APP_ID unprovisioned
39
+ ```
40
+
41
+ ### Loop Over Devices and Add to Provisioning Portal
42
+
43
+ This works only if you have already set up cupertino:
44
+
45
+ ```sh
46
+ $ gem install cupertino
47
+ $ ios login
48
+ ```
49
+
50
+ Then you can show all device (or all unprovisioned devices, see above) and add them to the portal:
51
+
52
+ ```sh
53
+ $ hockey devices:loop APP_ID
54
+ ```
55
+
56
+ Finally edit your profile:
57
+
58
+ ```sh
59
+ $ ios profiles:manage:devices distribution
60
+ ```
61
+
62
+ ## TODO
63
+
64
+ - Download profiles from the Provisioning Portal
65
+ - Upload modified profiles to HockeyApp
66
+ - Token management
67
+ - Some error handling
68
+
69
+ ## Contact
70
+
71
+ Thomas Dohmke & HockeyApp
72
+
73
+ - http://twitter.com/ashtom
74
+ - http://twitter.com/hockeyapp
75
+ - support@hockeyapp.net
76
+
77
+ ## License
78
+
79
+ Infinite Loop is available under the MIT license. See the LICENSE file for more info.
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env rake
2
+ require "bundler/gem_tasks"
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'commander/import'
4
+ require 'terminal-table'
5
+ require 'term/ansicolor'
6
+ require 'netrc'
7
+
8
+ require 'infinite'
9
+
10
+ HighLine.track_eof = false # Fix for built-in Ruby
11
+
12
+ program :version, Infinite::VERSION
13
+ program :description, 'A command-line interface for HockeyApp'
14
+
15
+ program :help, 'Author', 'Thomas Dohmke <thomas@hockeyapp.net>'
16
+ program :help, 'Website', 'http://hockeyapp.net'
17
+ program :help_formatter, :compact
18
+
19
+ default_command :help
20
+
21
+ require 'infinite/loop'
@@ -0,0 +1,22 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "infinite"
4
+
5
+ Gem::Specification.new do |gem|
6
+ gem.authors = ["Thomas Dohmke"]
7
+ gem.email = ["thomas@dohmke.de"]
8
+ gem.description = "A command-line interface for HockeyApp"
9
+ gem.summary = "Infinite Loop"
10
+ gem.homepage = ""
11
+
12
+ gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
13
+ gem.files = `git ls-files`.split("\n")
14
+ gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
15
+ gem.name = "infinite-loop"
16
+ gem.require_paths = ["lib"]
17
+ gem.version = Infinite::VERSION
18
+
19
+ gem.add_dependency "cupertino"
20
+ gem.add_dependency "rest-client"
21
+ gem.add_dependency "json"
22
+ end
@@ -0,0 +1,4 @@
1
+ module Infinite
2
+ VERSION = '0.1.0'
3
+ HOSTNAME = 'rink.hockeyapp.net'
4
+ end
@@ -0,0 +1,3 @@
1
+ require "infinite/loop/agent"
2
+ require "infinite/loop/helpers"
3
+ require "infinite/loop/commands"
@@ -0,0 +1,62 @@
1
+ require "json"
2
+ require "rest-client"
3
+
4
+ module Infinite
5
+ module Loop
6
+ class Agent
7
+ BASE_URL = "https://rink.hockeyapp.net/api/2/"
8
+
9
+ def initialize
10
+ netrc = Netrc.read
11
+ @token = netrc[Infinite::HOSTNAME].first unless netrc[Infinite::HOSTNAME].nil?
12
+ end
13
+
14
+ def list_apps(release_type_string = nil)
15
+ response = RestClient.get "#{BASE_URL}apps", { "X-HockeyAppToken" => @token }
16
+ apps = JSON.parse(response)["apps"]
17
+ apps.reject! { |app| app["release_type"] != release_type(release_type_string) } unless release_type_string.nil?
18
+ apps
19
+ end
20
+
21
+ def list_devices(app_id, unprovisioned = nil)
22
+ response = RestClient.get "#{BASE_URL}apps/#{app_id}/devices?unprovisioned=#{unprovisioned.to_s == "unprovisioned" ? 1 : 0}", {"X-HockeyAppToken" => @token }
23
+ devices = JSON.parse(response)["devices"]
24
+ devices
25
+ end
26
+
27
+ def list_tokens(user, pass)
28
+ response = RestClient::Request.new(:method => :get, :url => "#{BASE_URL}auth_tokens", :user => user, :password => pass).execute
29
+ tokens = JSON.parse(response.to_str)["tokens"]
30
+ tokens
31
+ end
32
+
33
+ def create_token(user, pass)
34
+ response = RestClient::Request.new(:method => :post, :url => "#{BASE_URL}auth_tokens", :user => user, :password => pass).execute
35
+ tokens = JSON.parse(response.to_str)["tokens"]
36
+ tokens
37
+ end
38
+
39
+ def release_type(string)
40
+ case string
41
+ when "beta"
42
+ 0
43
+ when "live"
44
+ 1
45
+ when "alpha"
46
+ 2
47
+ end
48
+ end
49
+
50
+ def release_type_string(value)
51
+ case value.to_i
52
+ when 0
53
+ "beta"
54
+ when 1
55
+ "live"
56
+ when 2
57
+ "alpha"
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,6 @@
1
+ include Infinite::Loop::Helpers
2
+
3
+ require 'Infinite/loop/commands/apps'
4
+ require 'Infinite/loop/commands/devices'
5
+ require 'Infinite/loop/commands/login'
6
+ require 'Infinite/loop/commands/logout'
@@ -0,0 +1,28 @@
1
+ command :'apps:list' do |c|
2
+ c.syntax = 'hockey apps:list'
3
+ c.summary = 'Lists the Name and ID of Apps on HockeyApp'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ if args.nil? or args.empty?
8
+ apps = try { agent.list_apps }
9
+ else
10
+ apps = try { agent.list_apps(args.first) }
11
+ end
12
+
13
+ title = "Listing Apps"
14
+ table = Terminal::Table.new :title => title do |t|
15
+ t << ["Title", "Platform", "Release Type", "App ID"]
16
+ t.add_separator
17
+ apps.compact.each do |app|
18
+ t << [
19
+ app["title"],
20
+ app["platform"],
21
+ agent.release_type_string(app["release_type"]),
22
+ app["public_identifier"]
23
+ ]
24
+ end
25
+ puts t
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,74 @@
1
+ command :'devices:list' do |c|
2
+ c.syntax = 'hockey devices:list'
3
+ c.summary = 'Lists the Devices of an App on HockeyApp'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ say_error "Missing arguments, expected App ID" and abort if args.nil? or args.empty?
8
+
9
+ devices = try { agent.list_devices(args[0], (args.length > 1 ? args[1] : nil)) }
10
+ title = "Listing Devices"
11
+ table = Terminal::Table.new :title => title do |t|
12
+ t << ["Device Name", "Device Identifier"]
13
+ t.add_separator
14
+ devices.compact.each do |device|
15
+ t << [
16
+ device["name"],
17
+ device["udid"]
18
+ ]
19
+ end
20
+ puts t
21
+ end
22
+ end
23
+ end
24
+
25
+ command :'devices:loop' do |c|
26
+ c.syntax = 'hockey devices:list'
27
+ c.summary = 'Add the Devices of an App on HockeyApp to the Provisioning Portal'
28
+ c.description = ''
29
+
30
+ c.action do |args, options|
31
+ say_error "Missing arguments, expected App ID" and abort if args.nil? or args.empty?
32
+
33
+ devices = try { agent.list_devices(args[0], (args.length > 1 ? args[1] : nil)) }
34
+ title = "Listing Devices"
35
+ table = Terminal::Table.new :title => title do |t|
36
+ t << ["#", "Device Name", "Device Identifier"]
37
+ t.add_separator
38
+ index = 0
39
+ devices.compact.each do |device|
40
+ t << [
41
+ "#{index + 1}",
42
+ device["name"],
43
+ device["udid"]
44
+ ]
45
+ index += 1
46
+ end
47
+
48
+ looping = true
49
+ while looping
50
+ puts t
51
+ selected = ask "Add device by #, or all devices (a), or quit (q):"
52
+ puts
53
+
54
+ case selected
55
+ when 'q'
56
+ add = nil
57
+ looping = false
58
+ when 'a'
59
+ add = devices
60
+ else
61
+ add = [devices[selected.to_i - 1]] if selected.to_i >= 1 and selected.to_i <= index
62
+ end
63
+
64
+ unless add.nil?
65
+ ext_args = []
66
+ add.each do |device|
67
+ ext_args << "\"#{device["name"]}=#{device["udid"]}\""
68
+ end
69
+ system "ios devices:add #{ext_args.join(" ")}"
70
+ end
71
+ end
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,24 @@
1
+ command :login do |c|
2
+ c.syntax = 'hockey login'
3
+ c.summary = 'Sign in to HockeyApp and fetch or create token'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ say_warning "You are already authenticated" if Netrc.read[Infinite::HOSTNAME]
8
+
9
+ user = ask "Email:"
10
+ pass = password "Password:"
11
+
12
+ tokens = agent.list_tokens(user, pass)
13
+ tokens.reject! { |token| token["rights"].to_i != 2 }
14
+ if tokens.length == 0
15
+ tokens = agent.create_token(user, pass)
16
+ end
17
+
18
+ netrc = Netrc.read
19
+ netrc[Infinite::HOSTNAME] = tokens.first["token"], "X"
20
+ netrc.save
21
+
22
+ say_ok "API token saved"
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ command :logout do |c|
2
+ c.syntax = 'hockey logout'
3
+ c.summary = 'Remove API token'
4
+ c.description = ''
5
+
6
+ c.action do |args, options|
7
+ say_error "You are not authenticated" and abort unless Netrc.read[Infinite::HOSTNAME]
8
+
9
+ netrc = Netrc.read
10
+ netrc.delete(Infinite::HOSTNAME)
11
+ netrc.save
12
+
13
+ say_ok "API token removed"
14
+ end
15
+ end
@@ -0,0 +1,28 @@
1
+ class String
2
+ include Term::ANSIColor
3
+ end
4
+
5
+ module Infinite
6
+ module Loop
7
+ module Helpers
8
+ def agent
9
+ @agent = Infinite::Loop::Agent.new unless @agent
10
+ @agent
11
+ end
12
+
13
+ def pluralize(n, singular, plural = nil)
14
+ n.to_i == 1 ? "1 #{singular}" : "#{n} #{plural || singular + 's'}"
15
+ end
16
+
17
+ def try
18
+ return unless block_given?
19
+
20
+ begin
21
+ yield
22
+ #rescue UnsuccessfulAuthenticationError
23
+ # say_error "Could not authenticate with HockeyApp." and abort
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
metadata ADDED
@@ -0,0 +1,95 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: infinite-loop
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Thomas Dohmke
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-17 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: cupertino
16
+ requirement: &70213216552340 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70213216552340
25
+ - !ruby/object:Gem::Dependency
26
+ name: rest-client
27
+ requirement: &70213216551520 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70213216551520
36
+ - !ruby/object:Gem::Dependency
37
+ name: json
38
+ requirement: &70213216550540 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *70213216550540
47
+ description: A command-line interface for HockeyApp
48
+ email:
49
+ - thomas@dohmke.de
50
+ executables:
51
+ - hockey
52
+ extensions: []
53
+ extra_rdoc_files: []
54
+ files:
55
+ - .gitignore
56
+ - Gemfile
57
+ - LICENSE
58
+ - README.md
59
+ - Rakefile
60
+ - bin/hockey
61
+ - infinite-loop.gemspec
62
+ - lib/infinite.rb
63
+ - lib/infinite/loop.rb
64
+ - lib/infinite/loop/agent.rb
65
+ - lib/infinite/loop/commands.rb
66
+ - lib/infinite/loop/commands/apps.rb
67
+ - lib/infinite/loop/commands/devices.rb
68
+ - lib/infinite/loop/commands/login.rb
69
+ - lib/infinite/loop/commands/logout.rb
70
+ - lib/infinite/loop/helpers.rb
71
+ homepage: ''
72
+ licenses: []
73
+ post_install_message:
74
+ rdoc_options: []
75
+ require_paths:
76
+ - lib
77
+ required_ruby_version: !ruby/object:Gem::Requirement
78
+ none: false
79
+ requirements:
80
+ - - ! '>='
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ required_rubygems_version: !ruby/object:Gem::Requirement
84
+ none: false
85
+ requirements:
86
+ - - ! '>='
87
+ - !ruby/object:Gem::Version
88
+ version: '0'
89
+ requirements: []
90
+ rubyforge_project:
91
+ rubygems_version: 1.8.17
92
+ signing_key:
93
+ specification_version: 3
94
+ summary: Infinite Loop
95
+ test_files: []