ios_build_kit 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/setup"
2
+
3
+ gemspec = eval(File.read("ios_build_kit.gemspec"))
4
+
5
+ task :build => "#{gemspec.full_name}.gem"
6
+
7
+ file "#{gemspec.full_name}.gem" => gemspec.files + ["ios_build_kit.gemspec"] do
8
+ system "gem build ios_build_kit.gemspec"
9
+ end
data/bin/buildkit ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
4
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
5
+
6
+ require 'ios_build_kit'
7
+
8
+ args = ARGV.dup
9
+ ARGV.clear
10
+
11
+ config_file = args[0]
12
+
13
+ system "clear"
14
+
15
+ BuildKit::Utilities::Console.terminate_with_err "BuildKit requires a configuration file to run, see: (http://github.com/adamwaite/iOS-Build-Kit)." if config_file.nil?
16
+
17
+ BuildKit.start_with_configuration config_file
Binary file
@@ -0,0 +1,31 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+
4
+ require "ios_build_kit/version"
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = "ios_build_kit"
8
+ s.authors = ["Adam Waite"]
9
+ s.email = "adam@adamjwaite.co.uk"
10
+ s.homepage = "https://github.com/adamwaite/iOS-Build-Kit"
11
+ s.version = BuildKit::VERSION
12
+ s.platform = Gem::Platform::RUBY
13
+ s.summary = "iOS Build Kit"
14
+ s.description = "iOS Build Tool CLI - Increment version • Decorate icon • Build app • Run unit tests • Create ipa artefact"
15
+
16
+ s.add_dependency "commander", "~> 4.1"
17
+ s.add_dependency "json", "~> 1.8"
18
+ s.add_dependency "paint", "~> 0.8"
19
+ s.add_dependency "nomad-cli", "~> 0.0.2"
20
+ s.add_dependency "rmagick", '~> 2.13'
21
+
22
+ s.add_development_dependency "bundler"
23
+ s.add_development_dependency "rspec"
24
+ s.add_development_dependency "rake"
25
+
26
+ s.files = Dir["./**/*"].reject { |file| file =~ /\.\/(bin|log|pkg|script|spec|test|vendor|example|resources)/ }
27
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
28
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
29
+ s.require_paths = ["lib"]
30
+
31
+ end
@@ -0,0 +1,12 @@
1
+ module BuildKit
2
+
3
+ Dir["#{File.dirname(__FILE__)}/ios_build_kit/**/*.rb"].each { |f| load(f) }
4
+
5
+ def self.start_with_configuration config
6
+ BuildKit::Utilities::Assertions.assert_files_exist [config]
7
+ BuildKit::Utilities::Console.header_msg "BuildKit Run Started"
8
+ runner = BuildKit::Runner::TaskRunner.new({ config_file: config })
9
+ runner.run_tasks!
10
+ end
11
+
12
+ end
@@ -0,0 +1,24 @@
1
+ module BuildKit
2
+
3
+ module Tasks
4
+
5
+ class BuildKitTask
6
+
7
+ attr_reader :runner, :config, :task_options
8
+
9
+ def initialize(attributes = {})
10
+ prepare_task_with_runner_and_options! attributes[:runner], attributes[:opts]
11
+ end
12
+
13
+ def prepare_task_with_runner_and_options! runner, opts
14
+ @runner = runner
15
+ @config = runner.config
16
+ @task_options = opts
17
+ assert_requirements
18
+ end
19
+
20
+ end
21
+
22
+ end
23
+
24
+ end
@@ -0,0 +1,13 @@
1
+ require 'ostruct'
2
+
3
+ module BuildKit
4
+
5
+ module Runner
6
+
7
+ class TaskRunnerConfig < OpenStruct
8
+
9
+ end
10
+
11
+ end
12
+
13
+ end
@@ -0,0 +1,82 @@
1
+ module BuildKit
2
+
3
+ require 'yaml'
4
+
5
+ module Runner
6
+
7
+ class TaskRunner
8
+
9
+ attr_reader :config, :preferences, :tasks, :outputs, :store
10
+
11
+ def initialize(attributes = {})
12
+ passed = hash_from_yaml attributes[:config_file]
13
+ @config = TaskRunnerConfig.new(passed[:configuration]).freeze
14
+ @preferences = TaskRunnerConfig.new (passed[:preferences]).freeze
15
+ prepare_task_queue! passed[:tasks]
16
+ @store = {}
17
+ @outputs = {}
18
+ end
19
+
20
+ def run_tasks!
21
+ @tasks[:raw].each do |task_name, task_opts|
22
+ if task_opts[:run]
23
+ @tasks[:running] = task_name
24
+ BuildKit::Utilities::Console.header_msg "Running Task: #{task_name}"
25
+ BuildKit::Tasks.send task_name, self, task_opts[:options]
26
+ else
27
+ BuildKit::Utilities::Console.header_msg "Skipping Task: #{task_name}"
28
+ end
29
+ end
30
+ all_tasks_completed
31
+ end
32
+
33
+ def has_completed_task? task
34
+ @tasks[:completed].include? task
35
+ end
36
+
37
+ def task_completed! task, success_message, output
38
+ @tasks[:completed] << task
39
+ BuildKit::Utilities::Console.success_msg success_message
40
+ @outputs[task] = output
41
+ end
42
+
43
+ private
44
+
45
+ def hash_from_yaml file
46
+ YAML.load_file(file)
47
+ end
48
+
49
+ def prepare_task_queue! tasks
50
+ @tasks = { raw: {}, run: [], skip: [], completed: [], running: nil }
51
+ @tasks[:raw] = tasks.freeze
52
+ @tasks[:run] = tasks.select { |k, v| v[:run] == true }.map do |k, v|
53
+ t = Hash.new
54
+ t[k] = { run: v[:run], options: v[:options] }
55
+ t
56
+ end.freeze
57
+ @tasks[:skip] = tasks.select { |k, v| v[:run] == false }.map do |k, v|
58
+ t = Hash.new
59
+ t[k] = { run: v[:run], options: v[:options] }
60
+ t
61
+ end.freeze
62
+ @tasks[:run].freeze
63
+ @tasks[:skip].freeze
64
+ end
65
+
66
+ def all_tasks_completed
67
+ unless @preferences.reports.nil?
68
+ if File.exists? @preferences.reports
69
+ build_report = BuildKit::Utilities::Reporter::create_report self
70
+ BuildKit::Utilities::Console.success_msg "BuildKit run report created at: #{build_report}"
71
+ else
72
+ puts "Warning: Report not created. Invalid directory specified: #{@preferences.reports}"
73
+ end
74
+ end
75
+ BuildKit::Utilities::Console.success_msg "\n😃 BuildKit Run Completed! Ran #{@tasks[:completed].count} tasks successfully!\n\n"
76
+ end
77
+
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,94 @@
1
+ module BuildKit
2
+
3
+ module Tasks
4
+
5
+ def self.create_ipa runner, task_opts
6
+ task = CreateIPATask.new({ runner: runner, opts: task_opts })
7
+ task.run!
8
+ end
9
+
10
+ private
11
+
12
+ class CreateIPATask < BuildKitTask
13
+
14
+ attr_accessor :artefact_filename
15
+
16
+ def initialize(attributes = {})
17
+ super
18
+ warn_about_missing_plist_config if @config.info_plist.nil?
19
+ end
20
+
21
+ def run!
22
+ build_artefact_filename!
23
+ run_command!
24
+ complete_task!
25
+ end
26
+
27
+ private
28
+
29
+ def assert_requirements
30
+ BuildKit::Utilities::Assertions.assert_tasks_completed [:xcode_build], @runner
31
+ BuildKit::Utilities::Assertions.assert_required_config [:code_sign, :provisioning_profile], @runner
32
+ BuildKit::Utilities::Assertions.assert_files_exist [@config.provisioning_profile]
33
+ end
34
+
35
+ def warn_about_missing_plist_config
36
+ BuildKit.warning_msg "Provide the :info_plist option in the config file to include the version number in the ipa file name"
37
+ end
38
+
39
+ def build_artefact_filename!
40
+ name = @config.app_name.dup
41
+ if (!@config.info_plist.nil? and File.exists? @config.info_plist)
42
+ name << "-"
43
+ if @runner.has_completed_task? :increment_version
44
+ name << @runner.store[:new_version_number][:full]
45
+ else
46
+ name << BuildKit::Utilities::VersionNumber.plist_version_number[:full]
47
+ end
48
+ end
49
+ name << "-"
50
+ name << Time.now.to_i.to_s
51
+ name << ".ipa"
52
+ @artefact_filename = name
53
+ end
54
+
55
+ def artefact_full_path
56
+ build_artefact_filename! if @artefact_filename.nil?
57
+ @config.build_dir + @artefact_filename
58
+ end
59
+
60
+ def existing_ipa_count
61
+ Dir["#{@build_dir}*.ipa"].length
62
+ end
63
+
64
+ def build_command
65
+ workspace_arg = "-workspace \"#{@config.workspace}\""
66
+ sdk_arg = "-sdk #{@config.sdk}"
67
+ build_file_arg = "-v \"#{@config.build_dir}#{@config.app_name}.app\""
68
+ output_file_arg = "-o \"#{artefact_full_path}\""
69
+ code_sign_arg = "--sign #{@config.code_sign}"
70
+ provisioning_arg = "--embed \"#{@config.provisioning_profile}\""
71
+ "xcrun #{sdk_arg} PackageApplication #{build_file_arg} #{output_file_arg} #{provisioning_arg}"
72
+ end
73
+
74
+ def run_command!
75
+ command = build_command
76
+ @output = %x[#{command}]
77
+ puts @output if @task_options[:log]
78
+ end
79
+
80
+ def ipa_created_successfully?
81
+ File.exists? artefact_full_path
82
+ end
83
+
84
+ def complete_task!
85
+ runner.store[:artefact_created] = artefact_full_path if ipa_created_successfully?
86
+ message = (ipa_created_successfully?) ? "create_ipa completed, ipa at: #{artefact_full_path}" : "create_ipa task completed but the ipa was not created"
87
+ runner.task_completed! :create_ipa, message, @output
88
+ end
89
+
90
+ end
91
+
92
+ end
93
+
94
+ end
@@ -0,0 +1,106 @@
1
+ module BuildKit
2
+
3
+ require 'rmagick'
4
+
5
+ module Tasks
6
+
7
+ def self.decorate_icon runner, task_opts
8
+ task = DecorateIconTask.new({ runner: runner, opts: task_opts })
9
+ task.run!
10
+ end
11
+
12
+ private
13
+
14
+ class DecorateIconTask < BuildKitTask
15
+
16
+ attr_reader :decorated_icons
17
+
18
+ def initialize(attributes = {})
19
+ super
20
+ @decorated_icons = []
21
+ end
22
+
23
+ def run!
24
+ decorate_icons!
25
+ complete_task!
26
+ end
27
+
28
+ private
29
+
30
+ def assert_requirements
31
+ BuildKit::Utilities::Assertions.assert_required_config [:info_plist, :icon_dir], @runner
32
+ BuildKit::Utilities::Assertions.assert_files_exist [@config.info_plist, @config.icon_dir]
33
+ end
34
+
35
+ def version_number_to_draw
36
+ if @runner.has_completed_task? :increment_version
37
+ @runner.store[:new_version_number][:full]
38
+ else
39
+ BuildKit::Utilities::VersionNumber.plist_version_number(runner.config.info_plist)[:full]
40
+ end
41
+ end
42
+
43
+ def icon_files_to_decorate
44
+ to_decorate = []
45
+ Dir.glob("#{runner.config[:icon_dir]}*.png").each do |filename|
46
+ next if filename.include? "Decorated"
47
+ to_decorate << filename
48
+ end
49
+ to_decorate
50
+ end
51
+
52
+ def decorate_icons!
53
+ icon_files_to_decorate.each do |img_path|
54
+ @decorated_icons << create_decorated_version_of(img_path)
55
+ end
56
+ end
57
+
58
+ def create_decorated_version_of icon_path
59
+ original = Magick::ImageList.new icon_path
60
+ decorated_icon = original.copy
61
+
62
+ icon_dimension = original.rows
63
+
64
+ background = Magick::Draw.new
65
+ background.fill_opacity(0.75)
66
+ background.rectangle(0, icon_dimension - (icon_dimension * 0.225), icon_dimension, icon_dimension)
67
+ background.draw decorated_icon
68
+
69
+ annotation_params = {
70
+ gravity: Magick::SouthGravity,
71
+ pointsize: icon_dimension * 0.11 ,
72
+ stroke: 'transparent',
73
+ fill: '#FFF',
74
+ font_family: "Helvetica CY",
75
+ font_weight: Magick::BoldWeight
76
+ }
77
+
78
+ version_text = Magick::Draw.new
79
+ version_text.annotate(decorated_icon, 0, 0, 0, icon_dimension * 0.05 , "#{version_number_to_draw}") do
80
+ self.gravity = annotation_params[:gravity]
81
+ self.pointsize = annotation_params[:pointsize]
82
+ self.stroke = annotation_params[:stroke]
83
+ self.fill = annotation_params[:fill]
84
+ self.font_family = annotation_params[:font_family]
85
+ self.font_weight = annotation_params[:font_weight]
86
+ end
87
+
88
+ original_img_filename = File.basename icon_path
89
+ new_img_filename = "Decorated-" + original_img_filename
90
+ new_img_full_path = icon_path.gsub(original_img_filename, new_img_filename)
91
+
92
+ decorated_icon.write(new_img_full_path)
93
+
94
+ new_img_full_path
95
+ end
96
+
97
+ def complete_task!
98
+ message = "Icons have been decorated with #{version_number_to_draw}. They are here: " + @decorated_icons.join(",")
99
+ @runner.task_completed! :decorate_icons, message, message
100
+ end
101
+
102
+ end
103
+
104
+ end
105
+
106
+ end
@@ -0,0 +1,55 @@
1
+ module BuildKit
2
+
3
+ module Tasks
4
+
5
+ def self.increment_version runner, task_opts
6
+ task = IncrementVersionTask.new({ runner: runner, opts: task_opts })
7
+ task.run!
8
+ end
9
+
10
+ private
11
+
12
+ class IncrementVersionTask < BuildKitTask
13
+
14
+ attr_reader :existing_version_number, :new_version_number
15
+
16
+ def run!
17
+ read_existing_version!
18
+ calculate_new_version!
19
+ write_new_version!
20
+ complete_task!
21
+ end
22
+
23
+ private
24
+
25
+ def assert_requirements
26
+ BuildKit::Utilities::Assertions.assert_files_exist [@config.info_plist]
27
+ end
28
+
29
+ def read_existing_version!
30
+ @existing_version_number = BuildKit::Utilities::VersionNumber.plist_version_number @config.info_plist
31
+ @runner.store[:existing_version_number] = @existing_version_number
32
+ end
33
+
34
+ def calculate_new_version!
35
+ incremented_build_number = @existing_version_number[:build] + 1
36
+ @new_version_number = BuildKit::Utilities::VersionNumber.hash_from_version_and_build @existing_version_number[:major_minor_revision], incremented_build_number
37
+ @runner.store[:new_version_number] = @new_version_number
38
+ end
39
+
40
+ def write_new_version!
41
+ BuildKit::Utilities::PlistPal.write_value_in_plist(@config.info_plist, "CFBundleShortVersionString", @new_version_number[:major_minor_revision] )
42
+ BuildKit::Utilities::PlistPal.write_value_in_plist(@config.info_plist, "CFBundleVersion", @new_version_number[:build] )
43
+ end
44
+
45
+ def complete_task!
46
+ output = "incremented version number from #{@existing_version_number[:full]} to #{@new_version_number[:full]}"
47
+ message = output + " and written to plist successfully"
48
+ @runner.task_completed! :increment_version, message, output
49
+ end
50
+
51
+ end
52
+
53
+ end
54
+
55
+ end