troops 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (8) hide show
  1. data/Gemfile +10 -0
  2. data/LICENSE +20 -0
  3. data/README.md +108 -0
  4. data/Rakefile +41 -0
  5. data/bin/troops +40 -0
  6. data/lib/troops.rb +136 -0
  7. data/lib/troops/configuration.rb +110 -0
  8. metadata +126 -0
data/Gemfile ADDED
@@ -0,0 +1,10 @@
1
+ source "http://rubygems.org"
2
+
3
+ gem "betabuilder", ">= 0.4.7.1"
4
+ gem "thor"
5
+ gem "rake"
6
+
7
+ group :development do
8
+ gem "bundler", "~> 1.0.0"
9
+ gem "jeweler", "~> 1.6.4"
10
+ end
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2011 Jelle Vandebeeck
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,108 @@
1
+ # TROOPS
2
+
3
+ iOS deployment to [TestFlight](http://testflightapp.com) with the [betabuilder](http://rubygems.org/gems/betabuilder) gem.
4
+
5
+ ## Installation
6
+
7
+ Simply install the gem:
8
+
9
+ gem install troops
10
+
11
+ ### Configuration files
12
+
13
+ There are 2 kind of configuration files, there needs to be a global file & file defined for each project. The files are always named `.troops` and resides in your home folder (for the global file) or in your project folder (for the project dependent file).
14
+
15
+ ### Global file
16
+
17
+ This `.troops`-file only needs to contain your API Token from TestFlight. You can find this token on the 'Your Account' page. Here is how the file needs to be formatted:
18
+
19
+ api_token: "thisismymegaawesometoken"
20
+
21
+ ### Project file
22
+
23
+ The project's '.troops' file contains the Team Token from your TestFlight Team. and some environmental properties that you can change. The Team Token can be found on the Team Info page.
24
+
25
+ Next to the token there are some other setting that you can define such as the environment you wish to deploy to (ex. Ad Hoc, Release...), or you can specify the target.
26
+
27
+ team_token: "thisismyawesometeamtoken"
28
+
29
+ staging:
30
+ target: "My App"
31
+ environment: "Ad Hoc"
32
+ disitribution_list: ["developers"]
33
+
34
+ production:
35
+ target: "My App"
36
+ environment: "Release"
37
+ disitribution_list: ["developers", "testers"]
38
+
39
+ Add this file to your project folder.
40
+
41
+ ## Usage
42
+
43
+ ### Archive builds
44
+
45
+ Archive your application by running the following command:
46
+
47
+ troops archive
48
+
49
+ This always uses the staging 'environment' to build the correct target. You can specify an environment by adding it as an argument:
50
+
51
+ troops archive production
52
+
53
+ ### Deploy to TestFlight
54
+
55
+ Deploy your application by running the following command:
56
+
57
+ troops deploy
58
+
59
+ This always uses the **staging** 'environment' to build the correct target. You can specify an environment by adding it as an argument:
60
+
61
+ troops deploy production
62
+
63
+ This command doesn't archive the build, if you want to archive while deploying, add the `--archive` argument.
64
+
65
+ troops deploy production --archive
66
+
67
+ To distribute the build to a disitribution group add the `--distribute` argument. This will send an email to the persons belonging to the distribution list defined in the project `.troops` file.
68
+
69
+ troops deploy production --distribute
70
+
71
+ ### Debug
72
+
73
+ There is also a `--log` argument that helps you debug if there are problems with your build. The betabuilder gem generates some folers & outpur files that are always removed by troops unless you specify the `--logs`argument.
74
+
75
+ * build
76
+ * build.output
77
+ * pkg
78
+
79
+ With the arg these remain inside your project folder.
80
+
81
+ troops deploy production --log
82
+
83
+ When you finished debugging you can just throw away the generated folder & files or run the following command to do it for you:
84
+
85
+ troops clean
86
+
87
+ ## License
88
+
89
+ Copyright (c) 2011 Jelle Vandebeeck
90
+
91
+ Permission is hereby granted, free of charge, to any person obtaining
92
+ a copy of this software and associated documentation files (the
93
+ "Software"), to deal in the Software without restriction, including
94
+ without limitation the rights to use, copy, modify, merge, publish,
95
+ distribute, sublicense, and/or sell copies of the Software, and to
96
+ permit persons to whom the Software is furnished to do so, subject to
97
+ the following conditions:
98
+
99
+ The above copyright notice and this permission notice shall be
100
+ included in all copies or substantial portions of the Software.
101
+
102
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
103
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
104
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
105
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
106
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
107
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
108
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Rakefile ADDED
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+
3
+ require 'rubygems'
4
+ require 'bundler'
5
+ begin
6
+ Bundler.setup(:default, :development)
7
+ rescue Bundler::BundlerError => e
8
+ $stderr.puts e.message
9
+ $stderr.puts "Run `bundle install` to install missing gems"
10
+ exit e.status_code
11
+ end
12
+ require 'rake'
13
+
14
+ require 'jeweler'
15
+ Jeweler::Tasks.new do |gem|
16
+ gem.name = "troops"
17
+ gem.homepage = "http://github.com/fousa/troops"
18
+ gem.license = "MIT"
19
+ gem.summary = %Q{Deploy your iOS apps to TestFlight with betabuilder}
20
+ gem.description = %Q{Deploy iOS apps with betabuilder}
21
+ gem.email = "jelle@fousa.be"
22
+ gem.authors = ["Jelle Vandebeeck"]
23
+ gem.executables = ['troops']
24
+ # dependencies defined in Gemfile
25
+ gem.add_runtime_dependency 'betabuilder'
26
+ gem.require_paths = ["lib"]
27
+ gem.files = [
28
+ "Rakefile",
29
+ "Gemfile",
30
+ "bin/troops",
31
+ "lib/troops.rb",
32
+ "lib/troops/configuration.rb",
33
+ ]
34
+ gem.version = "0.2.0"
35
+ gem.extra_rdoc_files = [
36
+ "README.md",
37
+ "LICENSE"
38
+ ]
39
+ gem.rdoc_options = ["--main", "README.md"]
40
+ end
41
+ Jeweler::RubygemsDotOrgTasks.new
data/bin/troops ADDED
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/ruby
2
+
3
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
4
+ require "rubygems"
5
+ require "troops"
6
+ require "thor"
7
+
8
+ module Wasko
9
+ class CLI < Thor
10
+ include Thor::Actions
11
+
12
+ desc "clean", "Remove the folders & output files generated"
13
+ def clean
14
+ Troops.clean
15
+ end
16
+
17
+ desc "archive ENVIRONMENT", "archive the iOS application"
18
+ method_options :log => :boolean, :alias => :string
19
+ def archive(environment="staging")
20
+ Troops.archive({
21
+ :environment => environment,
22
+ :log => options.log? || false
23
+ })
24
+ end
25
+
26
+ desc "deploy ENVIRONMENT", "deploy the iOS application to testflight"
27
+ method_options :archive => :boolean, :alias => :string
28
+ method_options :distribute => :boolean, :alias => :string
29
+ method_options :log => :boolean, :alias => :string
30
+ def deploy(environment="staging")
31
+ Troops.deploy({
32
+ :environment => environment,
33
+ :needs_to_archive => options.archive? || false,
34
+ :needs_to_disitribute => options.distribute? || false,
35
+ :log => options.log? || false
36
+ })
37
+ end
38
+ end
39
+ end
40
+ Wasko::CLI.start
data/lib/troops.rb ADDED
@@ -0,0 +1,136 @@
1
+ require "troops/configuration"
2
+
3
+ require "rubygems"
4
+ require "betabuilder"
5
+
6
+ module Troops
7
+ class << self
8
+ def clean
9
+ clear_builds
10
+ end
11
+
12
+ def archive(args)
13
+ @environment = args[:environment]
14
+ @log = args[:log]
15
+
16
+ $stdout.reopen("output.txt", "w") unless @log
17
+ warn "--- Start archiving"
18
+
19
+ configure do
20
+ beta_build = build_task
21
+
22
+ archive_build beta_build
23
+
24
+ clear_builds unless @log
25
+ end
26
+ end
27
+
28
+ def deploy(args)
29
+ @environment = args[:environment]
30
+ @needs_to_archive = args[:needs_to_archive]
31
+ @needs_to_distribute = args[:needs_to_distribute]
32
+ @log = args[:log]
33
+
34
+ $stdout.reopen("output.txt", "w") unless @log
35
+ warn "--- Start deploying"
36
+
37
+ configure do
38
+ get_release_notes
39
+ @release_notes = "No release notes specified in troops" if @release_notes.nil? || @release_notes.strip == ""
40
+
41
+ beta_build = build_task
42
+ beta_config = archive_build beta_build if @needs_to_archive
43
+
44
+ deploy_build_to_testflight beta_build
45
+
46
+ clear_builds unless @log
47
+ end
48
+ end
49
+
50
+ private
51
+
52
+ def get_release_notes
53
+ warn "--- Enter the TestFlight release notes (hit enter 2 times to finish)"
54
+
55
+ @release_notes = gets_until_match(/\n{2}$/).strip
56
+ end
57
+
58
+ def gets_until_match(pattern, string = "")
59
+ if (string += STDIN.gets) =~ pattern
60
+ string
61
+ else
62
+ gets_until_match(pattern, string)
63
+ end
64
+ end
65
+
66
+ def configure(&block)
67
+ warn "--- Checking configuration"
68
+
69
+ @config = Troops::Configuration.config @environment
70
+ unless @config.nil?
71
+ yield
72
+ end
73
+ end
74
+
75
+ def build_task
76
+ task = BetaBuilder::Tasks.new do |beta_config|
77
+ beta_config.xcode4_archive_mode = true
78
+
79
+ beta_config.target = @config[@environment]["target"]
80
+ beta_config.configuration = @config[@environment]["configuration"]
81
+
82
+ beta_config.deploy_using(:testflight) do |testflight|
83
+ testflight.api_token = @config["api_token"]
84
+ testflight.team_token = @config["team_token"]
85
+ testflight.distribution_lists = @config[@environment]["distribution_list"] if @needs_to_distribute && @config[@environment]["distribution_list"]
86
+ testflight.generate_release_notes do
87
+ @release_notes
88
+ end
89
+ end
90
+ end
91
+ beta_build = task.instance_eval { @configuration }
92
+
93
+ build task, beta_build
94
+
95
+ beta_build
96
+ end
97
+
98
+ def build(task, beta_build)
99
+ warn "--- Building the application"
100
+
101
+ task.xcodebuild(beta_build.build_arguments, "build")
102
+ end
103
+
104
+ def archive_build(beta_build)
105
+ beta_archive = BetaBuilder.archive(beta_build)
106
+ beta_config = beta_archive.instance_eval { @configuration }
107
+ output_path = beta_archive.save_to(beta_config.archive_path)
108
+
109
+ warn "--- Archive saved to #{output_path}."
110
+
111
+ beta_config
112
+ end
113
+
114
+ def deploy_build_to_testflight(beta_build)
115
+ warn "--- Uploading to TestFlight"
116
+
117
+ FileUtils.rm_rf('pkg') && FileUtils.mkdir_p('pkg')
118
+ FileUtils.mkdir_p("pkg/Payload")
119
+ FileUtils.mv(beta_build.built_app_path, "pkg/Payload/#{beta_build.app_file_name}")
120
+ Dir.chdir("pkg") do
121
+ system("zip -r '#{beta_build.ipa_name}' Payload")
122
+ end
123
+ FileUtils.mkdir('pkg/dist')
124
+ FileUtils.mv("pkg/#{beta_build.ipa_name}", "pkg/dist")
125
+
126
+ beta_build.deployment_strategy.prepare
127
+ beta_build.deployment_strategy.deploy
128
+ end
129
+
130
+ def clear_builds
131
+ warn "--- Clean the output folders & files"
132
+
133
+ %w{output.txt pkg build.output build}.each { |f| FileUtils.rm_rf f }
134
+ end
135
+ end
136
+ end
@@ -0,0 +1,110 @@
1
+ require "fileutils"
2
+ require 'yaml'
3
+
4
+ module Troops
5
+ # This class will handle all things considering
6
+ # loading and saving configuration. It should work
7
+ # like this.
8
+ #
9
+ # There are 2 kinds of configurations:
10
+ # * the project dependent one, has a .troops file with
11
+ # some configuration for the project
12
+ # * a user dependent one in the home directory of
13
+ # the user
14
+ #
15
+ class Configuration
16
+ class << self
17
+ def config(environment)
18
+ config_hash = yamlize
19
+ if config_hash["team_token"].nil?
20
+ puts ""
21
+ puts "======================================================================================="
22
+ puts "================================== TROOPS ============================================="
23
+ puts "======================================================================================="
24
+ puts "=== You have to set your TestFlight 'team_token' in your ~/.troops file. ==="
25
+ puts "=== Here is an example on how the .troop file should look: ==="
26
+ puts "=== ==="
27
+ puts "=== team_token: 'thisisyourawesometeamtoken' ==="
28
+ puts "=== ==="
29
+ puts "=== You can find your Team Token on your Team Info page on http://testflightapp.com ==="
30
+ puts "======================================================================================="
31
+ puts "======================================================================================="
32
+ puts ""
33
+ elsif config_hash["api_token"].nil?
34
+ puts ""
35
+ puts "============================================================================================="
36
+ puts "================================== TROOPS ==================================================="
37
+ puts "============================================================================================="
38
+ puts "=== You have to set your TestFlight 'api_token' in your .troops file inside this project. ==="
39
+ puts "=== Here is an example on how the .troops file should look: ==="
40
+ puts "=== ==="
41
+ puts "=== api_token: 'thisisyourawesomeapitoken' ==="
42
+ puts "=== production: ==="
43
+ puts "=== configuration: 'Release' ==="
44
+ puts "=== target: 'The Release iOS App Name' ==="
45
+ puts "=== staging: ==="
46
+ puts "=== configuration: 'Ad Hoc' ==="
47
+ puts "=== target: 'The Ad Hoc iOS App Name' ==="
48
+ puts "=== ==="
49
+ puts "=== You can find your Team Token on Your Account page on http://testflightapp.com ==="
50
+ puts "============================================================================================="
51
+ puts "============================================================================================="
52
+ puts ""
53
+ elsif config_hash[environment].nil?
54
+ puts ""
55
+ puts "============================================================================================="
56
+ puts "================================== TROOPS ==================================================="
57
+ puts "============================================================================================="
58
+ puts "=== You have to set your environment variable in your .troops file. ==="
59
+ puts "=== Here is an example on how the .troops file should look: ==="
60
+ puts "=== ==="
61
+ puts "=== api_token: 'thisisyourawesomeapitoken' ==="
62
+ puts "=== production: ==="
63
+ puts "=== configuration: 'Release' ==="
64
+ puts "=== target: 'The Release iOS App Name' ==="
65
+ puts "=== staging: ==="
66
+ puts "=== configuration: 'Ad Hoc' ==="
67
+ puts "=== target: 'The Ad Hoc iOS App Name' ==="
68
+ puts "============================================================================================="
69
+ puts "============================================================================================="
70
+ puts ""
71
+ else
72
+ config_hash
73
+ end
74
+ end
75
+
76
+ # Setup the color theme with the hash.
77
+ def yamlize
78
+ user_hash = {}
79
+ user_hash = YAML::load File.open(troops_user_config)
80
+ user_hash = {} unless Hash === user_hash
81
+
82
+ project_hash = {}
83
+ project_hash = YAML::load File.open(troops_project_config)
84
+ project_hash = {} unless Hash === project_hash
85
+
86
+ project_hash.merge(user_hash)
87
+ end
88
+
89
+ # All user dependent config files are stored in `~/.troops`
90
+ def troops_user_config
91
+ configurize "HOME"
92
+ end
93
+
94
+ # All project dependent config files are stored in `.troops`
95
+ def troops_project_config
96
+ configurize "PWD"
97
+ end
98
+
99
+ private
100
+
101
+ def configurize(env_type="HOME")
102
+ troops_path = File.join(ENV[env_type], ".troops")
103
+ unless File.exists?(troops_path)
104
+ File.open(troops_path, 'w')
105
+ end
106
+ troops_path
107
+ end
108
+ end
109
+ end
110
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: troops
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.0
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Jelle Vandebeeck
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-12-17 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: betabuilder
16
+ requirement: &70227761277980 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 0.4.7.1
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70227761277980
25
+ - !ruby/object:Gem::Dependency
26
+ name: thor
27
+ requirement: &70227761275940 !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: *70227761275940
36
+ - !ruby/object:Gem::Dependency
37
+ name: rake
38
+ requirement: &70227761255900 !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: *70227761255900
47
+ - !ruby/object:Gem::Dependency
48
+ name: bundler
49
+ requirement: &70227761245420 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: 1.0.0
55
+ type: :development
56
+ prerelease: false
57
+ version_requirements: *70227761245420
58
+ - !ruby/object:Gem::Dependency
59
+ name: jeweler
60
+ requirement: &70227761214800 !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ~>
64
+ - !ruby/object:Gem::Version
65
+ version: 1.6.4
66
+ type: :development
67
+ prerelease: false
68
+ version_requirements: *70227761214800
69
+ - !ruby/object:Gem::Dependency
70
+ name: betabuilder
71
+ requirement: &70227761206420 !ruby/object:Gem::Requirement
72
+ none: false
73
+ requirements:
74
+ - - ! '>='
75
+ - !ruby/object:Gem::Version
76
+ version: '0'
77
+ type: :runtime
78
+ prerelease: false
79
+ version_requirements: *70227761206420
80
+ description: Deploy iOS apps with betabuilder
81
+ email: jelle@fousa.be
82
+ executables:
83
+ - troops
84
+ extensions: []
85
+ extra_rdoc_files:
86
+ - LICENSE
87
+ - README.md
88
+ files:
89
+ - Gemfile
90
+ - Rakefile
91
+ - bin/troops
92
+ - lib/troops.rb
93
+ - lib/troops/configuration.rb
94
+ - LICENSE
95
+ - README.md
96
+ homepage: http://github.com/fousa/troops
97
+ licenses:
98
+ - MIT
99
+ post_install_message:
100
+ rdoc_options:
101
+ - --main
102
+ - README.md
103
+ require_paths:
104
+ - lib
105
+ required_ruby_version: !ruby/object:Gem::Requirement
106
+ none: false
107
+ requirements:
108
+ - - ! '>='
109
+ - !ruby/object:Gem::Version
110
+ version: '0'
111
+ segments:
112
+ - 0
113
+ hash: 913480742456072202
114
+ required_rubygems_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ! '>='
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 1.8.10
123
+ signing_key:
124
+ specification_version: 3
125
+ summary: Deploy your iOS apps to TestFlight with betabuilder
126
+ test_files: []