thrust 0.2.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/bin/thrust +8 -1
- data/lib/config/android_example.yml +17 -0
- data/lib/config/ios_example.yml +39 -0
- data/lib/tasks/cedar.rake +26 -18
- data/lib/tasks/testflight.rake +3 -3
- data/lib/tasks/version.rake +12 -0
- data/lib/thrust/android/deploy.rb +0 -11
- data/lib/thrust/android/deploy_provider.rb +13 -0
- data/lib/thrust/android/tools.rb +19 -13
- data/lib/thrust/config.rb +1 -1
- data/lib/thrust/executor.rb +9 -7
- data/lib/thrust/git.rb +10 -9
- data/lib/thrust/ios/agv_tool.rb +13 -0
- data/lib/thrust/ios/cedar.rb +8 -4
- data/lib/thrust/ios/deploy.rb +3 -12
- data/lib/thrust/ios/deploy_provider.rb +15 -0
- data/lib/thrust/ios/x_code_tools.rb +46 -53
- data/lib/thrust/ios/x_code_tools_provider.rb +10 -0
- data/lib/thrust/tasks.rb +3 -3
- data/lib/thrust/testflight.rb +5 -4
- data/lib/thrust.rb +4 -0
- metadata +21 -14
- data/lib/config/example.yml +0 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 978a630b927682d5514cf9ce5b71ce2bc2c9a9ff
|
4
|
+
data.tar.gz: ca9c565b330db40e39c02a7ca6ee600ae1a1a682
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 483178b25da64bc6d343d3032fc60b4d0bf12fdf5380794564a4bec13f2dc0e97dd6424f4111ff06c83ce891d71d5ce5e30c48ae784b0ecb8824f91142edcbe8
|
7
|
+
data.tar.gz: 79ea4ddc3b9ad3879d0572a354922b7a1d2ac4450f1134ee2cdf53103a916e6c3414487d6801458165adc573924c530c0c6ceb467a38f57586a722ca35d9123d
|
data/bin/thrust
CHANGED
@@ -20,7 +20,14 @@ File.open(rakefile, 'a') do |f|
|
|
20
20
|
f.puts "require 'thrust/tasks'"
|
21
21
|
end
|
22
22
|
|
23
|
-
|
23
|
+
if File.exists?('AndroidManifest.xml')
|
24
|
+
example_file_name = 'android_example.yml'
|
25
|
+
else
|
26
|
+
example_file_name = 'ios_example.yml'
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
FileUtils.cp(File.join(thrust_root, 'lib', 'config', example_file_name), File.join(project_root, 'thrust.example.yml'))
|
24
31
|
puts ''
|
25
32
|
puts " To finish installation of " + "Thrust".green + ", rename:\n\n"
|
26
33
|
puts " #{project_root}/thrust.example.yml\n".blue
|
@@ -0,0 +1,17 @@
|
|
1
|
+
thrust_version: 0.3
|
2
|
+
project_name: My Great Project
|
3
|
+
app_name: My Great App
|
4
|
+
|
5
|
+
testflight:
|
6
|
+
api_token: 'testflight api token'
|
7
|
+
team_token: 'testflight team token'
|
8
|
+
|
9
|
+
deployment_targets:
|
10
|
+
staging:
|
11
|
+
distribution_list: Developers
|
12
|
+
notify: true
|
13
|
+
note_generation_method: autotag # If you set this value, it will auto-generate the deploy notes from the commit history. Optional.
|
14
|
+
|
15
|
+
demo:
|
16
|
+
distribution_list: Beta Testers
|
17
|
+
notify: true
|
@@ -0,0 +1,39 @@
|
|
1
|
+
thrust_version: 0.3
|
2
|
+
project_name: My Great Project # do not use if building with an xcode workspace
|
3
|
+
# workspace_name: My Workspace # use if building with an xcode workspace
|
4
|
+
app_name: My Great App
|
5
|
+
ios_distribution_certificate: 'Name of Distribution Signing Certificate'
|
6
|
+
ios_sim_binary: 'ios-sim' # or wax-sim. iOS only.
|
7
|
+
|
8
|
+
testflight:
|
9
|
+
api_token: 'testflight api token' # To find your App Token, follow the instructions at: http://help.testflightapp.com/customer/portal/articles/829956-what-does-the-api-token-do-
|
10
|
+
team_token: 'testflight team token' # To find your Team Token, follow the instructions at: http://help.testflightapp.com/customer/portal/articles/829942-how-do-i-find-my-team-token-
|
11
|
+
|
12
|
+
deployment_targets:
|
13
|
+
staging:
|
14
|
+
distribution_list: Developers # This is the name of a TestFlight distribution list
|
15
|
+
notify: true # Whether to notify people on the distribution list about this deployment
|
16
|
+
note_generation_method: autotag # If you set this value, it will auto-generate the deploy notes from the commit history. Optional.
|
17
|
+
ios_target: MyGreatAppTarget # Name of the build target. Optional, defaults to app name. iOS only.
|
18
|
+
ios_build_configuration: Release # iOS only
|
19
|
+
ios_provisioning_search_query: 'query to find Provisioning Profile' # iOS only. Optional.
|
20
|
+
|
21
|
+
demo:
|
22
|
+
distribution_list: Beta Testers
|
23
|
+
notify: true
|
24
|
+
|
25
|
+
ios_spec_targets:
|
26
|
+
specs: # This is the name of the rake task: `rake specs`
|
27
|
+
target: UISpecs # name of the build target
|
28
|
+
# scheme: Specs (My Great App) # use in addition to target when you want to use a scheme (necessary if you are building with an xcode workspace)
|
29
|
+
build_configuration: Debug # name of the build configuration
|
30
|
+
build_sdk: iphonesimulator7.0 # SDK used to build the target. Optional, defaults to latest iphonesimulator.
|
31
|
+
runtime_sdk: 7.0 # SDK used to run the target. Not optional.
|
32
|
+
device: ipad # Device to run the specs on. Optional, defaults to iPhone.
|
33
|
+
|
34
|
+
integration:
|
35
|
+
target: IntegrationSpecs
|
36
|
+
# scheme: IntegrationSpecs (My Great App) # use in addition to target when you want to use a scheme (necessary if you are building with an xcode workspace)
|
37
|
+
build_configuration: Release
|
38
|
+
build_sdk: macosx
|
39
|
+
runtime_sdk: macosx
|
data/lib/tasks/cedar.rake
CHANGED
@@ -3,6 +3,8 @@ require 'tmpdir'
|
|
3
3
|
require File.expand_path('../../thrust', __FILE__)
|
4
4
|
|
5
5
|
@thrust = Thrust::Config.make(Dir.getwd, File.join(Dir.getwd, 'thrust.yml'))
|
6
|
+
@xcode_tools_provider = Thrust::IOS::XCodeToolsProvider.new
|
7
|
+
@executor = Thrust::Executor.new
|
6
8
|
|
7
9
|
desc 'Trim whitespace'
|
8
10
|
task :trim do
|
@@ -16,51 +18,57 @@ task :trim do
|
|
16
18
|
AWK
|
17
19
|
awk_statement.gsub!(%r{\s+}, " ")
|
18
20
|
|
19
|
-
|
21
|
+
@executor.system_or_exit %Q[git status --porcelain | awk '#{awk_statement}' | grep -e '.*\.[cmh]$' | xargs sed -i '' -e 's/ / /g;s/ *$//g;']
|
20
22
|
end
|
21
23
|
|
22
|
-
desc
|
24
|
+
desc 'Remove any focus from specs'
|
23
25
|
task :nof do
|
24
26
|
substitutions = focused_methods.map do |method|
|
25
27
|
unfocused_method = method.sub(/^f/, '')
|
26
28
|
"-e 's/#{method}/#{unfocused_method}/g;'"
|
27
29
|
end
|
28
30
|
|
29
|
-
|
31
|
+
@executor.system_or_exit %Q[ rake focused_specs | xargs -I filename sed -i '' #{substitutions.join(' ')} "filename" ]
|
30
32
|
end
|
31
33
|
|
32
|
-
desc
|
34
|
+
desc 'Print out names of files containing focused specs'
|
33
35
|
task :focused_specs do
|
34
36
|
pattern = focused_methods.join("\\|")
|
35
37
|
directories = @thrust.app_config['ios_spec_targets'].values.map {|h| h['target']}.join(' ')
|
36
|
-
|
38
|
+
@executor.system_or_exit %Q[ grep -l -r -e "\\(#{pattern}\\)" #{directories} | grep -v 'Frameworks' ; exit 0 ]
|
37
39
|
end
|
38
40
|
|
39
41
|
desc 'Clean all targets'
|
40
|
-
task :
|
41
|
-
|
42
|
-
xcode_tools = Thrust::IOS::XCodeTools.new($stdout, config, @thrust.build_dir, @thrust.app_config['project_name'])
|
43
|
-
xcode_tools.clean_build
|
44
|
-
end
|
42
|
+
task :clean do
|
43
|
+
xcode_tools_instance(nil).clean_build
|
45
44
|
end
|
46
45
|
|
46
|
+
desc 'Clean all targets (deprecated, use "clean")'
|
47
|
+
task :clean_build => :clean
|
48
|
+
|
47
49
|
(@thrust.app_config['ios_spec_targets'] || []).each do |task_name, target_info|
|
48
|
-
desc "Run the #{target_info['target']} target"
|
49
|
-
task task_name do
|
50
|
+
desc target_info['scheme'] ? "Run the #{target_info['scheme'].inspect} scheme" : "Run the #{target_info['target'].inspect} target"
|
51
|
+
task task_name, :runtime_sdk do |_, args|
|
50
52
|
build_configuration = target_info['build_configuration']
|
51
53
|
target = target_info['target']
|
54
|
+
scheme = target_info['scheme']
|
52
55
|
build_sdk = target_info['build_sdk'] || 'iphonesimulator' #build sdk - version you compile the code with
|
53
|
-
runtime_sdk = target_info['runtime_sdk'] #runtime sdk
|
56
|
+
runtime_sdk = args[:runtime_sdk] || target_info['runtime_sdk'] #runtime sdk
|
54
57
|
|
55
|
-
xcode_tools =
|
56
|
-
xcode_tools.
|
58
|
+
xcode_tools = xcode_tools_instance(build_configuration)
|
59
|
+
xcode_tools.build_scheme_or_target(scheme || target, build_sdk, 'i386')
|
57
60
|
|
58
|
-
cedar_success = Thrust::IOS::Cedar.run($stdout, build_configuration, target, runtime_sdk, build_sdk, target_info['device'], @thrust.build_dir, @thrust.app_config['ios_sim_binary'])
|
61
|
+
cedar_success = Thrust::IOS::Cedar.new.run($stdout, build_configuration, target, runtime_sdk, build_sdk, target_info['device'], @thrust.build_dir, @thrust.app_config['ios_sim_binary'])
|
59
62
|
|
60
|
-
|
63
|
+
exit(1) unless cedar_success
|
61
64
|
end
|
62
65
|
end
|
63
66
|
|
64
67
|
def focused_methods
|
65
|
-
|
68
|
+
%w(fit fcontext fdescribe).map { |method| "#{method}(@" }
|
69
|
+
end
|
70
|
+
|
71
|
+
def xcode_tools_instance(build_configuration)
|
72
|
+
tools_options = { project_name: @thrust.app_config['project_name'], workspace_name: @thrust.app_config['workspace_name'] }
|
73
|
+
@xcode_tools_provider.instance($stdout, build_configuration, @thrust.build_dir, tools_options)
|
66
74
|
end
|
data/lib/tasks/testflight.rake
CHANGED
@@ -11,14 +11,14 @@ namespace :testflight do
|
|
11
11
|
if android_project
|
12
12
|
desc "Deploy Android build to #{task_name} (use NOTIFY=false to prevent team notification)"
|
13
13
|
task task_name do |_, _|
|
14
|
-
Thrust::Android::
|
14
|
+
Thrust::Android::DeployProvider.new.instance(@thrust, deployment_config, task_name).run
|
15
15
|
|
16
16
|
Rake::Task['autotag:create'].invoke(task_name)
|
17
17
|
end
|
18
18
|
else
|
19
19
|
desc "Deploy iOS build to #{task_name} (use NOTIFY=false to prevent team notification)"
|
20
20
|
task task_name do |_, _|
|
21
|
-
Thrust::IOS::
|
21
|
+
Thrust::IOS::DeployProvider.new.instance(@thrust, deployment_config, task_name).run
|
22
22
|
|
23
23
|
Rake::Task['autotag:create'].invoke(task_name)
|
24
24
|
end
|
@@ -34,7 +34,7 @@ namespace :autotag do
|
|
34
34
|
desc 'Show the commit that is currently deployed to each environment'
|
35
35
|
task :list do
|
36
36
|
@thrust.app_config['deployment_targets'].each do |deployment_target, _|
|
37
|
-
puts Thrust::Git.new($stdout).commit_summary_for_last_deploy(deployment_target)
|
37
|
+
puts Thrust::Git.new(Thrust::Executor.new, $stdout).commit_summary_for_last_deploy(deployment_target)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require File.expand_path('../../thrust', __FILE__)
|
2
|
+
|
3
|
+
desc 'Set build number'
|
4
|
+
task :set_build_number, :build_number do |_, args|
|
5
|
+
executor = Thrust::Executor.new
|
6
|
+
|
7
|
+
if File.exists?('AndroidManifest.xml')
|
8
|
+
Thrust::Android::Tools.new(executor, $stdout).change_build_number(Time.now.utc.strftime('%y%m%d%H%M'), args[:build_number])
|
9
|
+
else
|
10
|
+
Thrust::IOS::AgvTool.new(executor, $stdout).change_build_number(args[:build_number])
|
11
|
+
end
|
12
|
+
end
|
@@ -1,15 +1,4 @@
|
|
1
1
|
class Thrust::Android::Deploy
|
2
|
-
def self.make(thrust_config, deployment_config, deployment_target)
|
3
|
-
tools = Thrust::Android::Tools.new($stdout)
|
4
|
-
git = Thrust::Git.new($stdout)
|
5
|
-
|
6
|
-
testflight_config = thrust_config.app_config['testflight']
|
7
|
-
testflight = Thrust::Testflight.new($stdout, $stdin, testflight_config['api_token'], testflight_config['team_token'])
|
8
|
-
|
9
|
-
autogenerate_notes = deployment_config['note_generation_method'] == 'autotag'
|
10
|
-
new($stdout, tools, git, testflight, deployment_config['notify'], deployment_config['distribution_list'], autogenerate_notes, deployment_target)
|
11
|
-
end
|
12
|
-
|
13
2
|
def initialize(out, tools, git, testflight, notify, distribution_list, autogenerate_notes, deployment_target)
|
14
3
|
@out = out
|
15
4
|
@tools = tools
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Thrust::Android::DeployProvider
|
2
|
+
def instance(thrust_config, deployment_config, deployment_target)
|
3
|
+
thrust_executor = Thrust::Executor.new
|
4
|
+
tools = Thrust::Android::Tools.new(thrust_executor, $stdout)
|
5
|
+
git = Thrust::Git.new(thrust_executor, $stdout)
|
6
|
+
|
7
|
+
testflight_config = thrust_config.app_config['testflight']
|
8
|
+
testflight = Thrust::Testflight.new(thrust_executor, $stdout, $stdin, testflight_config['api_token'], testflight_config['team_token'])
|
9
|
+
|
10
|
+
autogenerate_notes = deployment_config['note_generation_method'] == 'autotag'
|
11
|
+
Thrust::Android::Deploy.new($stdout, tools, git, testflight, deployment_config['notify'], deployment_config['distribution_list'], autogenerate_notes, deployment_target)
|
12
|
+
end
|
13
|
+
end
|
data/lib/thrust/android/tools.rb
CHANGED
@@ -1,33 +1,39 @@
|
|
1
1
|
require 'colorize'
|
2
2
|
|
3
3
|
class Thrust::Android::Tools
|
4
|
-
def initialize(out)
|
4
|
+
def initialize(thrust_executor, out)
|
5
|
+
@thrust_executor = thrust_executor
|
5
6
|
@out = out
|
6
|
-
|
7
|
-
if ENV['ANDROID_HOME'].nil?
|
8
|
-
if File.directory?('/usr/local/opt/android-sdk')
|
9
|
-
@out.puts 'Setting /usr/local/opt/android-sdk as ANDROID_HOME...'.magenta
|
10
|
-
ENV['ANDROID_HOME'] = '/usr/local/opt/android-sdk'
|
11
|
-
else
|
12
|
-
raise('**********Android is not installed. Run `brew install android`.**********')
|
13
|
-
end
|
14
|
-
end
|
15
7
|
end
|
16
8
|
|
17
9
|
def change_build_number(version_code, version_name)
|
18
|
-
|
10
|
+
@thrust_executor.system_or_exit(
|
19
11
|
"sed -i ''" +
|
20
12
|
" -e 's/android:versionCode=\"[0-9]*\"/android:versionCode=\"#{version_code}\"/'" +
|
21
13
|
" -e 's/android:versionName=\"\\([^ \"]*\\)[^\"]*\"/android:versionName=\"\\1 (#{version_name})\"/'" +
|
22
14
|
" AndroidManifest.xml")
|
23
|
-
|
15
|
+
@thrust_executor.system_or_exit(
|
24
16
|
"sed -i ''" +
|
25
17
|
" '1,/<version>/s/<version>\\([^- <]*\\)[^<]*<\\/version>/<version>\\1 (#{version_name})<\\/version>/'" +
|
26
18
|
" pom.xml")
|
27
19
|
end
|
28
20
|
|
29
21
|
def build_signed_release
|
30
|
-
|
22
|
+
verify_android_installed!
|
23
|
+
@thrust_executor.system_or_exit('mvn clean package -Prelease')
|
31
24
|
Dir.glob('target/*-signed-aligned.apk').first or raise 'Signed APK was not generated'
|
32
25
|
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def verify_android_installed!
|
30
|
+
if ENV['ANDROID_HOME'].nil?
|
31
|
+
if File.directory?('/usr/local/opt/android-sdk')
|
32
|
+
@out.puts 'Setting /usr/local/opt/android-sdk as ANDROID_HOME...'.magenta
|
33
|
+
ENV['ANDROID_HOME'] = '/usr/local/opt/android-sdk'
|
34
|
+
else
|
35
|
+
raise('**********Android is not installed. Run `brew install android`.**********')
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
33
39
|
end
|
data/lib/thrust/config.rb
CHANGED
data/lib/thrust/executor.rb
CHANGED
@@ -1,22 +1,24 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
class Thrust::Executor
|
2
|
+
CommandFailed = Class.new(StandardError)
|
3
|
+
|
4
|
+
def system_or_exit(cmd, output_file = nil)
|
5
|
+
system(cmd, output_file) or raise(CommandFailed, '******** Build failed ********')
|
4
6
|
end
|
5
7
|
|
6
|
-
def
|
8
|
+
def system(cmd, output_file = nil)
|
7
9
|
STDERR.puts "Executing #{cmd}"
|
8
10
|
cmd += " > #{output_file}" if output_file
|
9
11
|
Kernel::system(cmd)
|
10
12
|
end
|
11
13
|
|
12
|
-
def
|
14
|
+
def capture_output_from_system(cmd)
|
13
15
|
captured_output = `#{cmd}`
|
14
|
-
raise '******** Build failed ********' if $?.exitstatus > 0
|
16
|
+
raise(CommandFailed, '******** Build failed ********') if $?.exitstatus > 0
|
15
17
|
|
16
18
|
captured_output
|
17
19
|
end
|
18
20
|
|
19
|
-
def
|
21
|
+
def check_command_for_failure(cmd)
|
20
22
|
STDERR.puts "Executing #{cmd} and checking for FAILURE"
|
21
23
|
result = %x[#{cmd} 2>&1]
|
22
24
|
STDERR.puts "Results:"
|
data/lib/thrust/git.rb
CHANGED
@@ -1,7 +1,8 @@
|
|
1
1
|
require 'colorize'
|
2
2
|
|
3
3
|
class Thrust::Git
|
4
|
-
def initialize(out)
|
4
|
+
def initialize(thrust_executor, out)
|
5
|
+
@thrust_executor = thrust_executor
|
5
6
|
@out = out
|
6
7
|
end
|
7
8
|
|
@@ -10,20 +11,20 @@ class Thrust::Git
|
|
10
11
|
@out.puts 'WARNING NOT CHECKING FOR CLEAN WORKING DIRECTORY'.red
|
11
12
|
else
|
12
13
|
@out.puts 'Checking for clean working tree...'
|
13
|
-
|
14
|
+
@thrust_executor.system_or_exit 'git diff-index --quiet HEAD'
|
14
15
|
end
|
15
16
|
end
|
16
17
|
|
17
18
|
def current_commit
|
18
|
-
|
19
|
+
@thrust_executor.capture_output_from_system('git log --format=format:%h -1').strip
|
19
20
|
end
|
20
21
|
|
21
22
|
def reset
|
22
|
-
|
23
|
+
@thrust_executor.system_or_exit('git reset --hard')
|
23
24
|
end
|
24
25
|
|
25
26
|
def checkout_file(filename)
|
26
|
-
|
27
|
+
@thrust_executor.system_or_exit("git checkout #{filename}")
|
27
28
|
end
|
28
29
|
|
29
30
|
def commit_summary_for_last_deploy(deployment_target)
|
@@ -36,13 +37,13 @@ class Thrust::Git
|
|
36
37
|
end
|
37
38
|
|
38
39
|
def generate_notes_for_deployment(deployment_target)
|
39
|
-
sha_of_latest_commit =
|
40
|
+
sha_of_latest_commit = @thrust_executor.capture_output_from_system('git rev-parse HEAD').strip
|
40
41
|
sha_of_latest_deployed_commit = latest_deployed_commit(deployment_target)
|
41
42
|
|
42
43
|
notes = Tempfile.new('deployment_notes')
|
43
44
|
|
44
45
|
if sha_of_latest_deployed_commit
|
45
|
-
|
46
|
+
@thrust_executor.system_or_exit("git log --oneline #{sha_of_latest_deployed_commit}...#{sha_of_latest_commit}", notes.path)
|
46
47
|
else
|
47
48
|
notes.puts(summary_for_commit(sha_of_latest_commit))
|
48
49
|
notes.close
|
@@ -54,11 +55,11 @@ class Thrust::Git
|
|
54
55
|
private
|
55
56
|
|
56
57
|
def summary_for_commit(sha)
|
57
|
-
|
58
|
+
@thrust_executor.capture_output_from_system("git log --oneline -n 1 #{sha}")
|
58
59
|
end
|
59
60
|
|
60
61
|
def latest_deployed_commit(deployment_target)
|
61
|
-
list =
|
62
|
+
list = @thrust_executor.capture_output_from_system("autotag list #{deployment_target}")
|
62
63
|
unless list.strip.empty?
|
63
64
|
list.split("\n").last.split(" ").first
|
64
65
|
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class Thrust::IOS::AgvTool
|
2
|
+
|
3
|
+
def initialize(thrust_executor, out)
|
4
|
+
@thrust_executor = thrust_executor
|
5
|
+
@out = out
|
6
|
+
@git = Thrust::Git.new(@thrust_executor, @out)
|
7
|
+
end
|
8
|
+
|
9
|
+
def change_build_number(build_number)
|
10
|
+
@thrust_executor.system_or_exit "agvtool new-version -all '#{build_number}'"
|
11
|
+
@git.checkout_file('*.xcodeproj')
|
12
|
+
end
|
13
|
+
end
|
data/lib/thrust/ios/cedar.rb
CHANGED
@@ -1,17 +1,21 @@
|
|
1
1
|
class Thrust::IOS::Cedar
|
2
2
|
|
3
|
-
def
|
3
|
+
def initialize(thrust_executor = Thrust::Executor.new)
|
4
|
+
@thrust_executor = thrust_executor
|
5
|
+
end
|
6
|
+
|
7
|
+
def run(out, build_configuration, target, runtime_sdk, build_sdk, device, build_dir, simulator_binary)
|
4
8
|
if build_sdk == 'macosx'
|
5
9
|
build_path = File.join(build_dir, build_configuration)
|
6
10
|
app_dir = File.join(build_path, target)
|
7
|
-
|
11
|
+
@thrust_executor.check_command_for_failure("DYLD_FRAMEWORK_PATH=#{build_path.inspect} #{app_dir}")
|
8
12
|
else
|
9
13
|
app_executable = File.join(build_dir, "#{build_configuration}-#{build_sdk}", "#{target}.app")
|
10
14
|
|
11
15
|
if simulator_binary =~ /waxim%/
|
12
|
-
|
16
|
+
@thrust_executor.check_command_for_failure(%Q[#{simulator_binary} -s #{runtime_sdk} -f #{device} -e CFFIXED_USER_HOME=#{Dir.tmpdir} -e CEDAR_HEADLESS_SPECS=1 -e CEDAR_REPORTER_CLASS=CDRDefaultReporter #{app_executable}])
|
13
17
|
elsif simulator_binary =~ /ios-sim$/
|
14
|
-
|
18
|
+
@thrust_executor.check_command_for_failure(%Q[#{simulator_binary} launch #{app_executable} --sdk #{runtime_sdk} --family #{device} --retina --tall --setenv CFFIXED_USER_HOME=#{Dir.tmpdir} --setenv CEDAR_HEADLESS_SPECS=1 --setenv CEDAR_REPORTER_CLASS=CDRDefaultReporter])
|
15
19
|
else
|
16
20
|
out.puts "Unknown binary for running specs: '#{simulator_binary}'"
|
17
21
|
false
|
data/lib/thrust/ios/deploy.rb
CHANGED
@@ -1,17 +1,8 @@
|
|
1
1
|
class Thrust::IOS::Deploy
|
2
|
-
def
|
3
|
-
build_configuration = deployment_config['ios_build_configuration']
|
4
|
-
x_code_tools = Thrust::IOS::XCodeTools.new($stdout, build_configuration, thrust_config.build_dir, thrust_config.app_config['project_name'])
|
5
|
-
git = Thrust::Git.new($stdout)
|
6
|
-
testflight_config = thrust_config.app_config['testflight']
|
7
|
-
testflight = Thrust::Testflight.new($stdout, $stdin, testflight_config['api_token'], testflight_config['team_token'])
|
8
|
-
|
9
|
-
new($stdout, x_code_tools, git, testflight, thrust_config, deployment_config, deployment_target)
|
10
|
-
end
|
11
|
-
|
12
|
-
def initialize(out, x_code_tools, git, testflight, thrust_config, deployment_config, deployment_target)
|
2
|
+
def initialize(out, x_code_tools, agv_tool, git, testflight, thrust_config, deployment_config, deployment_target)
|
13
3
|
@out = out
|
14
4
|
@x_code_tools = x_code_tools
|
5
|
+
@agv_tool = agv_tool
|
15
6
|
@git = git
|
16
7
|
@testflight = testflight
|
17
8
|
@thrust_config = thrust_config
|
@@ -21,7 +12,7 @@ class Thrust::IOS::Deploy
|
|
21
12
|
|
22
13
|
def run
|
23
14
|
@git.ensure_clean
|
24
|
-
@
|
15
|
+
@agv_tool.change_build_number(@git.current_commit)
|
25
16
|
|
26
17
|
app_name = @thrust_config.app_config['app_name']
|
27
18
|
target = @deployment_config['ios_target'] || app_name
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class Thrust::IOS::DeployProvider
|
2
|
+
def instance(thrust_config, deployment_config, deployment_target)
|
3
|
+
stdout = $stdout
|
4
|
+
thrust_executor = Thrust::Executor.new
|
5
|
+
build_configuration = deployment_config['ios_build_configuration']
|
6
|
+
tools_options = { project_name: thrust_config.app_config['project_name'], workspace_name: thrust_config.app_config['workspace_name'] }
|
7
|
+
x_code_tools = Thrust::IOS::XCodeToolsProvider.new.instance(stdout, build_configuration, thrust_config.build_dir, tools_options)
|
8
|
+
agv_tool = Thrust::IOS::AgvTool.new(thrust_executor, stdout)
|
9
|
+
git = Thrust::Git.new(thrust_executor, stdout)
|
10
|
+
testflight_config = thrust_config.app_config['testflight']
|
11
|
+
testflight = Thrust::Testflight.new(thrust_executor, stdout, $stdin, testflight_config['api_token'], testflight_config['team_token'])
|
12
|
+
|
13
|
+
Thrust::IOS::Deploy.new(stdout, x_code_tools, agv_tool, git, testflight, thrust_config, deployment_config, deployment_target)
|
14
|
+
end
|
15
|
+
end
|
@@ -1,33 +1,21 @@
|
|
1
1
|
class Thrust::IOS::XCodeTools
|
2
2
|
ProvisioningProfileNotFound = Class.new(StandardError)
|
3
3
|
|
4
|
-
def
|
5
|
-
|
6
|
-
match = /Build Configurations:(.+?)\n\n/m.match(output)
|
7
|
-
if match
|
8
|
-
match[1].strip.split("\n").map { |line| line.strip }
|
9
|
-
else
|
10
|
-
[]
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(out, build_configuration, build_directory, project_name)
|
4
|
+
def initialize(thrust_executor, out, build_configuration, build_directory, options = {})
|
5
|
+
@thrust_executor = thrust_executor
|
15
6
|
@out = out
|
16
|
-
@git = Thrust::Git.new(out)
|
7
|
+
@git = Thrust::Git.new(@thrust_executor, @out)
|
17
8
|
@build_configuration = build_configuration
|
18
9
|
@build_directory = build_directory
|
19
|
-
@project_name = project_name
|
20
|
-
|
21
|
-
|
22
|
-
def change_build_number(build_number)
|
23
|
-
Thrust::Executor.system_or_exit "agvtool new-version -all '#{build_number}'"
|
24
|
-
@git.checkout_file('*.xcodeproj')
|
10
|
+
@project_name = options[:project_name]
|
11
|
+
@workspace_name = options[:workspace_name]
|
12
|
+
raise "project_name OR workspace_name required" unless @project_name.nil? ^ @workspace_name.nil?
|
25
13
|
end
|
26
14
|
|
27
15
|
def cleanly_create_ipa(target, app_name, signing_identity, provision_search_query = nil)
|
28
16
|
clean_build
|
29
17
|
kill_simulator
|
30
|
-
|
18
|
+
build_scheme_or_target(target, 'iphoneos')
|
31
19
|
create_ipa(app_name, signing_identity, provision_search_query)
|
32
20
|
end
|
33
21
|
|
@@ -37,27 +25,21 @@ class Thrust::IOS::XCodeTools
|
|
37
25
|
|
38
26
|
def clean_build
|
39
27
|
@out.puts 'Cleaning...'
|
40
|
-
|
41
|
-
FileUtils.rm_rf(build_configuration_directory)
|
28
|
+
FileUtils.rm_rf(@build_directory)
|
42
29
|
end
|
43
30
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
31
|
+
def build_scheme_or_target(scheme_or_target, build_sdk, architecture=nil)
|
32
|
+
@out.puts "Building..."
|
33
|
+
run_xcode('build', build_sdk, scheme_or_target, architecture)
|
47
34
|
end
|
48
35
|
|
49
36
|
private
|
50
37
|
|
51
|
-
def build_target(target, build_sdk)
|
52
|
-
@out.puts "Building..."
|
53
|
-
run_xcode('build', build_sdk, target)
|
54
|
-
end
|
55
|
-
|
56
38
|
def kill_simulator
|
57
39
|
@out.puts('Killing simulator...')
|
58
|
-
|
59
|
-
|
60
|
-
|
40
|
+
@thrust_executor.system %q[killall -m -KILL "gdb"]
|
41
|
+
@thrust_executor.system %q[killall -m -KILL "otest"]
|
42
|
+
@thrust_executor.system %q[killall -m -KILL "iPhone Simulator"]
|
61
43
|
end
|
62
44
|
|
63
45
|
def provision_path(provision_search_query)
|
@@ -79,30 +61,37 @@ class Thrust::IOS::XCodeTools
|
|
79
61
|
"--sign '#{signing_identity}'",
|
80
62
|
"--embed '#{provision_path(provision_search_query)}'"
|
81
63
|
].join(' ')
|
82
|
-
|
64
|
+
@thrust_executor.system_or_exit(cmd)
|
83
65
|
ipa_filename
|
84
66
|
end
|
85
67
|
|
86
|
-
|
87
|
-
|
88
|
-
target_flag =
|
89
|
-
sdk_flag = sdk ? "-sdk #{sdk}" :
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
)
|
68
|
+
def run_xcode(build_command, sdk = nil, scheme_or_target = nil, architecture=nil)
|
69
|
+
architecture_flag = architecture ? "-arch #{architecture}" : nil
|
70
|
+
target_flag = @workspace_name ? "-scheme \"#{scheme_or_target}\"" : "-target \"#{scheme_or_target}\""
|
71
|
+
sdk_flag = sdk ? "-sdk #{sdk}" : nil
|
72
|
+
configuration_build_dir = File.join(@build_directory, "#{@build_configuration}-#{sdk}")
|
73
|
+
|
74
|
+
command = [
|
75
|
+
'set -o pipefail &&',
|
76
|
+
'xcodebuild',
|
77
|
+
project_or_workspace_flag,
|
78
|
+
architecture_flag,
|
79
|
+
target_flag,
|
80
|
+
"-configuration #{@build_configuration}",
|
81
|
+
sdk_flag,
|
82
|
+
"#{build_command}",
|
83
|
+
"SYMROOT=#{@build_directory.inspect}",
|
84
|
+
"CONFIGURATION_BUILD_DIR=#{configuration_build_dir.inspect}",
|
85
|
+
'2>&1',
|
86
|
+
"| grep -v 'backing file'"
|
87
|
+
].compact.join(' ')
|
88
|
+
output_file = output_file("#{@build_configuration}-#{build_command}")
|
89
|
+
begin
|
90
|
+
@thrust_executor.system_or_exit(command, output_file)
|
91
|
+
rescue Thrust::Executor::CommandFailed => e
|
92
|
+
@out.write File.read(output_file)
|
93
|
+
raise e
|
94
|
+
end
|
106
95
|
end
|
107
96
|
|
108
97
|
def output_file(target)
|
@@ -114,4 +103,8 @@ class Thrust::IOS::XCodeTools
|
|
114
103
|
|
115
104
|
File.join(output_dir, "#{target}.output").tap { |file| @out.puts "Output: #{file}" }
|
116
105
|
end
|
106
|
+
|
107
|
+
def project_or_workspace_flag
|
108
|
+
@workspace_name ? "-workspace #{@workspace_name}.xcworkspace" : "-project #{@project_name}.xcodeproj"
|
109
|
+
end
|
117
110
|
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class Thrust::IOS::XCodeToolsProvider
|
2
|
+
|
3
|
+
def initialize(thrust_executor = Thrust::Executor.new)
|
4
|
+
@thrust_executor = thrust_executor
|
5
|
+
end
|
6
|
+
|
7
|
+
def instance(out, build_configuration, build_directory, options)
|
8
|
+
Thrust::IOS::XCodeTools.new(@thrust_executor, out, build_configuration, build_directory, options)
|
9
|
+
end
|
10
|
+
end
|
data/lib/thrust/tasks.rb
CHANGED
@@ -1,3 +1,3 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
1
|
+
load File.expand_path("../../tasks/cedar.rake", __FILE__) unless File.exists?('AndroidManifest.xml')
|
2
|
+
load File.expand_path("../../tasks/testflight.rake", __FILE__)
|
3
|
+
load File.expand_path("../../tasks/version.rake", __FILE__)
|
data/lib/thrust/testflight.rb
CHANGED
@@ -1,8 +1,9 @@
|
|
1
1
|
class Thrust::Testflight
|
2
|
-
def initialize(out, input, api_token, team_token)
|
2
|
+
def initialize(thrust_executor, out, input, api_token, team_token)
|
3
|
+
@thrust_executor = thrust_executor
|
3
4
|
@out = out
|
4
5
|
@in = input
|
5
|
-
@git = Thrust::Git.new(@out)
|
6
|
+
@git = Thrust::Git.new(@thrust_executor, @out)
|
6
7
|
@api_token = api_token
|
7
8
|
@team_token = team_token
|
8
9
|
end
|
@@ -11,7 +12,7 @@ class Thrust::Testflight
|
|
11
12
|
if dsym_path
|
12
13
|
@out.puts 'Zipping dSYM...'
|
13
14
|
zipped_dsym_path = "#{dsym_path}.zip"
|
14
|
-
|
15
|
+
@thrust_executor.system_or_exit "zip -r -T -y '#{zipped_dsym_path}' '#{dsym_path}'"
|
15
16
|
@out.puts 'Done!'
|
16
17
|
end
|
17
18
|
|
@@ -22,7 +23,7 @@ class Thrust::Testflight
|
|
22
23
|
end
|
23
24
|
|
24
25
|
|
25
|
-
|
26
|
+
@thrust_executor.system_or_exit [
|
26
27
|
'curl http://testflightapp.com/api/builds.json',
|
27
28
|
"-F file=@#{package_file}",
|
28
29
|
("-F dsym=@#{zipped_dsym_path}" if dsym_path),
|
data/lib/thrust.rb
CHANGED
@@ -9,8 +9,12 @@ require 'thrust/testflight'
|
|
9
9
|
require 'thrust/user_prompt'
|
10
10
|
|
11
11
|
require 'thrust/android/deploy'
|
12
|
+
require 'thrust/android/deploy_provider'
|
12
13
|
require 'thrust/android/tools'
|
13
14
|
|
15
|
+
require 'thrust/ios/agv_tool'
|
14
16
|
require 'thrust/ios/cedar'
|
15
17
|
require 'thrust/ios/deploy'
|
18
|
+
require 'thrust/ios/deploy_provider'
|
16
19
|
require 'thrust/ios/x_code_tools'
|
20
|
+
require 'thrust/ios/x_code_tools_provider'
|
metadata
CHANGED
@@ -1,25 +1,26 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: thrust
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
|
-
-
|
8
|
-
-
|
9
|
-
-
|
7
|
+
- Aaron Levine
|
8
|
+
- Aaron VonderHaar
|
9
|
+
- Andrew Bruce
|
10
10
|
- Andrew Kitchen
|
11
|
-
- Tyler Schultz
|
12
|
-
- Wiley Kestner
|
13
11
|
- Brandon Liu
|
12
|
+
- Can Berk Güder
|
13
|
+
- Eugenia Dellapenna
|
14
14
|
- Jeff Hui
|
15
|
+
- Johnathon Britz
|
16
|
+
- Jonathan Barnes
|
17
|
+
- Michael McCormick
|
18
|
+
- Molly Trombley-McCann
|
15
19
|
- Philip Kuryloski
|
16
|
-
- Andrew Bruce
|
17
|
-
- Aaron Levine
|
18
|
-
- Eugenia Dellapenna
|
19
|
-
- Aaron VonderHaar
|
20
|
-
- Sheel Choksi
|
21
20
|
- Rachel Bobbins
|
22
|
-
-
|
21
|
+
- Sheel Choksi
|
22
|
+
- Tyler Schultz
|
23
|
+
- Wiley Kestner
|
23
24
|
autorequire:
|
24
25
|
bindir: bin
|
25
26
|
cert_chain: []
|
@@ -119,18 +120,24 @@ extensions: []
|
|
119
120
|
extra_rdoc_files: []
|
120
121
|
files:
|
121
122
|
- bin/thrust
|
122
|
-
- lib/config/
|
123
|
+
- lib/config/android_example.yml
|
124
|
+
- lib/config/ios_example.yml
|
123
125
|
- lib/tasks/cedar.rake
|
124
126
|
- lib/tasks/testflight.rake
|
127
|
+
- lib/tasks/version.rake
|
125
128
|
- lib/thrust.rb
|
126
129
|
- lib/thrust/android/deploy.rb
|
130
|
+
- lib/thrust/android/deploy_provider.rb
|
127
131
|
- lib/thrust/android/tools.rb
|
128
132
|
- lib/thrust/config.rb
|
129
133
|
- lib/thrust/executor.rb
|
130
134
|
- lib/thrust/git.rb
|
135
|
+
- lib/thrust/ios/agv_tool.rb
|
131
136
|
- lib/thrust/ios/cedar.rb
|
132
137
|
- lib/thrust/ios/deploy.rb
|
138
|
+
- lib/thrust/ios/deploy_provider.rb
|
133
139
|
- lib/thrust/ios/x_code_tools.rb
|
140
|
+
- lib/thrust/ios/x_code_tools_provider.rb
|
134
141
|
- lib/thrust/tasks.rb
|
135
142
|
- lib/thrust/testflight.rb
|
136
143
|
- lib/thrust/user_prompt.rb
|
@@ -154,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
154
161
|
version: '0'
|
155
162
|
requirements: []
|
156
163
|
rubyforge_project:
|
157
|
-
rubygems_version: 2.2.
|
164
|
+
rubygems_version: 2.2.2
|
158
165
|
signing_key:
|
159
166
|
specification_version: 4
|
160
167
|
summary: Thrust is a collection of rake tasks for iOS/Android development and deployment
|
data/lib/config/example.yml
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
thrust_version: 0.2
|
2
|
-
project_name: My Great Project
|
3
|
-
app_name: My Great App
|
4
|
-
ios_distribution_certificate: 'Name of Distribution Signing Certificate'
|
5
|
-
ios_sim_binary: 'ios-sim' # or wax-sim. iOS only.
|
6
|
-
|
7
|
-
testflight:
|
8
|
-
api_token: 'testflight api token'
|
9
|
-
team_token: 'testflight team token'
|
10
|
-
|
11
|
-
deployment_targets:
|
12
|
-
staging:
|
13
|
-
distribution_list: Developers
|
14
|
-
notify: true
|
15
|
-
note_generation_method: autotag # If you set this value, it will auto-generate the deploy notes from the commit history. Optional.
|
16
|
-
ios_target: MyGreatAppTarget # Name of the build target. Optional, defaults to app name. iOS only.
|
17
|
-
ios_build_configuration: Release # iOS only
|
18
|
-
ios_provisioning_search_query: 'query to find Provisioning Profile' # iOS only. Optional.
|
19
|
-
|
20
|
-
demo:
|
21
|
-
distribution_list: Beta Testers
|
22
|
-
notify: true
|
23
|
-
|
24
|
-
ios_spec_targets:
|
25
|
-
specs:
|
26
|
-
target: UISpecs # name of the build target
|
27
|
-
build_configuration: Debug # name of the build configuration
|
28
|
-
build_sdk: 6.1 # SDK used to build the target. Optional, defaults to iphonesimulator.
|
29
|
-
runtime_sdk: 7.0 # SDK used to run the target. Not optional.
|
30
|
-
device: ipad # Device to run the specs on. Optional, defaults to iPhone.
|
31
|
-
|
32
|
-
integration:
|
33
|
-
target: IntegrationSpecs
|
34
|
-
build_configuration: Release
|
35
|
-
build_sdk: macosx
|
36
|
-
runtime_sdk: macosx
|