ios_build_kit 0.0.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.
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