ios-box 0.2.1 → 0.2.3
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +33 -27
- data/bin/ios-box +1 -1
- data/ios-box.gemspec +5 -2
- data/lib/ios-box.rb +2 -6
- data/lib/ios-box/cli.rb +89 -86
- data/lib/ios-box/config.rb +30 -16
- data/lib/ios-box/deploy.rb +96 -0
- data/lib/ios-box/deploy/testflight.rb +35 -0
- data/lib/ios-box/iosbox.rb +122 -122
- data/lib/ios-box/tools.rb +6 -6
- data/lib/ios-box/tools/build.rb +41 -42
- data/lib/ios-box/tools/config.rb +36 -0
- data/lib/ios-box/tools/deploy.rb +179 -0
- data/lib/ios-box/tools/version.rb +28 -29
- data/lib/ios_box.rb +1 -1
- metadata +45 -9
- data/lib/ios-box/version.rb +0 -5
@@ -0,0 +1,36 @@
|
|
1
|
+
module IOSBox
|
2
|
+
module Tools
|
3
|
+
class Config < Thor
|
4
|
+
desc "show", "Displays current configuration information"
|
5
|
+
def show
|
6
|
+
shell.print_table IOSBox.new.config.to_a
|
7
|
+
end
|
8
|
+
|
9
|
+
desc "set key value", "Sets certain key to value value"
|
10
|
+
def set(key, value)
|
11
|
+
if ["true", "yes"].include?(value.downcase)
|
12
|
+
value = true
|
13
|
+
elsif ["false", "no"].include?(value.downcase)
|
14
|
+
value = false
|
15
|
+
end
|
16
|
+
|
17
|
+
config = IOSBox.new.config
|
18
|
+
# Split config
|
19
|
+
category, key = key.split(/\./)
|
20
|
+
if key.nil?
|
21
|
+
config.send("#{category}=", value)
|
22
|
+
else
|
23
|
+
if !config.send(category).kind_of?(Hash)
|
24
|
+
config.send("#{category}=", {})
|
25
|
+
end
|
26
|
+
config.send(category).send(:[]=, key, value)
|
27
|
+
end
|
28
|
+
|
29
|
+
# config.testflight = {}
|
30
|
+
# config.testflight['apikey'] = 'XXXX'
|
31
|
+
# # config.send("#{key}=", value)
|
32
|
+
config.save
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,179 @@
|
|
1
|
+
require 'ios-box/deploy'
|
2
|
+
require 'pbxproject'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module IOSBox
|
6
|
+
module Tools
|
7
|
+
class Deploy < Thor
|
8
|
+
include Thor::Actions
|
9
|
+
|
10
|
+
desc "add PROVIDER", "Configures deployment targets"
|
11
|
+
def add(provider)
|
12
|
+
iosbox = IOSBox.new
|
13
|
+
pbx = PBXProject::PBXProject.new :file => File.join(iosbox.project_dir, iosbox.config.project, "project.pbxproj")
|
14
|
+
pbx.parse
|
15
|
+
|
16
|
+
# Find all configuration lists and check if we have already Ad Hoc configuration
|
17
|
+
cfglists = pbx.find_item :type => PBXProject::PBXTypes::XCConfigurationList
|
18
|
+
cfglists.each do |cfg|
|
19
|
+
if cfg.buildConfigurations.select {|bc| bc.comment == "Ad Hoc"}.empty?
|
20
|
+
puts "Copy Release => Ad Hoc"
|
21
|
+
release = cfg.buildConfigurations.select {|bc| bc.comment == "Release"}.first.value
|
22
|
+
bc = pbx.find_item :guid => release, :type => PBXProject::PBXTypes::XCBuildConfiguration
|
23
|
+
adhoc = PBXProject::PBXTypes::XCBuildConfiguration.new
|
24
|
+
adhoc.comment = "Ad Hoc"
|
25
|
+
adhoc.name = PBXProject::PBXTypes::BasicValue.new(:value => '"Ad Hoc"')
|
26
|
+
adhoc.buildSettings = bc.buildSettings
|
27
|
+
pbx.add_item adhoc
|
28
|
+
|
29
|
+
cfg.buildConfigurations << PBXProject::PBXTypes::BasicValue.new(:value => adhoc.guid, :comment => "Ad Hoc")
|
30
|
+
cfg.defaultConfigurationName = "Release"
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
pbx.write_to :file => File.join(iosbox.project_dir, iosbox.config.project, "project.pbxproj")
|
35
|
+
|
36
|
+
# Copy scheme
|
37
|
+
xcuserdata = File.join(iosbox.project_dir, iosbox.config.project, "xcuserdata", "#{ENV['USER']}.xcuserdatad")
|
38
|
+
scheme = File.open(Dir[File.join(xcuserdata, "xcschemes", "*.xcscheme")].first)
|
39
|
+
deploy = File.join(xcuserdata, "xcschemes", "Deploy.xcscheme")
|
40
|
+
doc = Nokogiri::XML(scheme)
|
41
|
+
|
42
|
+
# Get identifier
|
43
|
+
blueprint_id = doc.xpath("//BuildableReference").first.attr("BlueprintIdentifier")
|
44
|
+
|
45
|
+
# Change configuration of Archive
|
46
|
+
action = doc.xpath("//ArchiveAction").first
|
47
|
+
action.attribute("buildConfiguration").value = "Ad Hoc"
|
48
|
+
# Add Post Action
|
49
|
+
Nokogiri::XML::Builder.with(action) do |xml|
|
50
|
+
xml.PostActions {
|
51
|
+
xml.ExecutionAction(:ActionType => "Xcode.IDEStandardExecutionActionsCore.ExecutionActionType.ShellScriptAction") {
|
52
|
+
xml.ActionContent(:title => "Run Script", :scriptText=> "(cd $PROJECT_DIR; ios-box deploy #{provider})") {
|
53
|
+
xml.EnvironmentBuildable {
|
54
|
+
xml.BuildableReference(
|
55
|
+
:BuildableIdentifier => "primary",
|
56
|
+
:BlueprintIdentifier => "C0B33A571451827A000B80A2",
|
57
|
+
:BuildableName => "ios.app",
|
58
|
+
:BlueprintName => "ios",
|
59
|
+
:ReferencedContainer => "container:ios.xcodeproj")
|
60
|
+
}
|
61
|
+
}
|
62
|
+
}
|
63
|
+
}
|
64
|
+
end
|
65
|
+
|
66
|
+
File.open(deploy, 'w') {|io| io.puts doc.to_xml }
|
67
|
+
|
68
|
+
# Configure provider
|
69
|
+
send(provider, "config")
|
70
|
+
end
|
71
|
+
|
72
|
+
desc "testflight", "Deploys latest built archive to TestFlight"
|
73
|
+
method_option :notes, :type => :string, :desc => "Supply build notes. If a file, notes are read from given file."
|
74
|
+
method_option :distribution, :type => :array, :desc => "Distribution list to deploy"
|
75
|
+
method_option :notify, :type => :boolean, :default => true, :desc => "Notify testers of new build"
|
76
|
+
method_option :replace, :type => :boolean, :default => true, :desc => "Replace existing build"
|
77
|
+
def testflight(config = nil)
|
78
|
+
iosbox = IOSBox.new
|
79
|
+
|
80
|
+
if config == "config"
|
81
|
+
# Config mode
|
82
|
+
iosbox.config.testflight ||= {}
|
83
|
+
iosbox.config.testflight['apitoken'] = shell.ask("Testflight API token:")
|
84
|
+
iosbox.config.testflight['teamtoken'] = shell.ask("Testflight Team token:")
|
85
|
+
iosbox.config.save
|
86
|
+
|
87
|
+
exit
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
tf = ::IOSBox::Deploy::Testflight.new iosbox
|
92
|
+
|
93
|
+
# Do we have archive path in buildcache
|
94
|
+
if ENV['XCODE_VERSION_ACTUAL'] and ENV['CONFIGURATION'] == "Ad Hoc"
|
95
|
+
# Always use fresh data if ran from XCode
|
96
|
+
prod_path = ENV['ARCHIVE_PATH']
|
97
|
+
# Update cache
|
98
|
+
puts iosbox.cache.inspect
|
99
|
+
iosbox.cache[:"ad hoc"][:archive_path] = ENV['ARCHIVE_PATH']
|
100
|
+
iosbox.cache.save
|
101
|
+
elsif iosbox.cache[:"ad hoc"][:archive_path]
|
102
|
+
# Otherwise use build cache if exists
|
103
|
+
prod_path = iosbox.cache[:"ad hoc"][:archive_path]
|
104
|
+
else
|
105
|
+
# Otherwise, require Xcode
|
106
|
+
require_xcode
|
107
|
+
end
|
108
|
+
|
109
|
+
# Check that we have required keys
|
110
|
+
if iosbox.config.testflight['apitoken'].nil?
|
111
|
+
shell.error "Please set TestFlight API token (ios-box config set testflight_apitoken XXXXXX)"
|
112
|
+
end
|
113
|
+
if iosbox.config.testflight['teamtoken'].nil?
|
114
|
+
shell.error "Please set TestFlight Team token (ios-box config set testflight_teamtoken XXXXXX)"
|
115
|
+
end
|
116
|
+
if iosbox.config.testflight['apitoken'].nil? or iosbox.config.testflight['teamtoken'].nil?
|
117
|
+
tf.notify :name => "Deployment Failed",
|
118
|
+
:title => "Testflight Deployment",
|
119
|
+
:error => "Testflight has not been configured. Please run ios-box deploy testflight config"
|
120
|
+
end
|
121
|
+
|
122
|
+
puts "Deploying to TestFlight... Please wait..."
|
123
|
+
ipa = tf.create_ipa prod_path
|
124
|
+
dsym = tf.create_dsym prod_path
|
125
|
+
|
126
|
+
# Creating build notes
|
127
|
+
if options['notes'].nil?
|
128
|
+
if iosbox.config.deploy['autonotes']
|
129
|
+
# Get last deployment
|
130
|
+
last_deployed = iosbox.config.testflight['lastdeploy'] || iosbox.git.log.last.id
|
131
|
+
# Get git changelog
|
132
|
+
notes = ""
|
133
|
+
iosbox.git.commits_between(last_deployed, 'HEAD').reverse_each do |commit|
|
134
|
+
notes << commit.authored_date.to_s + "\n"
|
135
|
+
notes << commit.authored_date.to_s.length.times.inject("") { |i,c| i + "=" } + "\n"
|
136
|
+
notes << commit.message + "\n"
|
137
|
+
end
|
138
|
+
end
|
139
|
+
else
|
140
|
+
if File.exists?(options['notes'])
|
141
|
+
notes = File.read(options['notes'])
|
142
|
+
else
|
143
|
+
notes = options['notes']
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
147
|
+
if notes.empty?
|
148
|
+
# Try to find TextMate
|
149
|
+
mate = %x{which mate}.strip
|
150
|
+
if File.exists?(mate)
|
151
|
+
f = Tempfile.new('notes')
|
152
|
+
f.write "Replace this with build notes."
|
153
|
+
f.close
|
154
|
+
system(mate, "--wait", f.path)
|
155
|
+
notes = File.read(f)
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
tf.deploy :file => ipa,
|
160
|
+
:apitoken => iosbox.config.testflight['apitoken'],
|
161
|
+
:teamtoken => iosbox.config.testflight['teamtoken'],
|
162
|
+
:notes => notes,
|
163
|
+
:dsym => dsym,
|
164
|
+
:distribution => options['distribution'],
|
165
|
+
:notify => options['notify'],
|
166
|
+
:replace => options['replace'],
|
167
|
+
:growl => iosbox.config.growl
|
168
|
+
end
|
169
|
+
|
170
|
+
private
|
171
|
+
def require_xcode
|
172
|
+
unless ENV['XCODE_VERSION_ACTUAL']
|
173
|
+
shell.error "This task must be run in XCode Environment"
|
174
|
+
exit
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
@@ -1,32 +1,31 @@
|
|
1
|
-
module
|
2
|
-
module
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
1
|
+
module IOSBox
|
2
|
+
module Tools
|
3
|
+
class Version < Thor
|
4
|
+
desc "show", "Displays current version information"
|
5
|
+
def show
|
6
|
+
version = IOSBox.new.version
|
7
|
+
|
8
|
+
|
9
|
+
puts " Short Version: #{version[:short]}"
|
10
|
+
puts " Bundle Version: #{version[:bundle]}"
|
11
|
+
puts " Technical: %1.4f" % version[:technical]
|
12
|
+
puts " Build Number: #{version[:build]}"
|
13
|
+
puts " Commit: #{version[:commit]}"
|
14
|
+
end
|
15
|
+
|
16
|
+
desc "build [BUILDNUM]", "Increments current build number or sets it to defined."
|
17
|
+
def build(buildnum = nil)
|
18
|
+
IOSBox.new.version.bump_build(buildnum)
|
19
|
+
end
|
20
|
+
|
21
|
+
desc "set VERSION", "Sets new marketing version"
|
22
|
+
def set(ver)
|
23
|
+
IOSBox.new.version.set_marketing(ver)
|
24
|
+
end
|
25
|
+
|
26
|
+
desc "bump [major|minor]", "Bumps marketings version by one"
|
27
|
+
def bump(type = :patch)
|
28
|
+
IOSBox.new.version.bump_marketing(type.to_s.downcase.to_sym)
|
30
29
|
end
|
31
30
|
end
|
32
31
|
end
|
data/lib/ios_box.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ios-box
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.3
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,11 +9,11 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-10-
|
12
|
+
date: 2011-10-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: thor
|
16
|
-
requirement: &
|
16
|
+
requirement: &70165439353500 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ! '>='
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: '0'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70165439353500
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: grit
|
27
|
-
requirement: &
|
27
|
+
requirement: &70165439352880 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ! '>='
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: '0'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70165439352880
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: plist
|
38
|
-
requirement: &
|
38
|
+
requirement: &70165439352280 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,7 +43,40 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70165439352280
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: rubyzip
|
49
|
+
requirement: &70165439351660 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70165439351660
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: rest-client
|
60
|
+
requirement: &70165439350880 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *70165439350880
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: nokogiri
|
71
|
+
requirement: &70165439350360 !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: *70165439350360
|
47
80
|
description: Include atuomatic vesion conrol for you XCode projects.
|
48
81
|
email:
|
49
82
|
- mikko@owlforestry.com
|
@@ -66,12 +99,15 @@ files:
|
|
66
99
|
- lib/ios-box.rb
|
67
100
|
- lib/ios-box/cli.rb
|
68
101
|
- lib/ios-box/config.rb
|
102
|
+
- lib/ios-box/deploy.rb
|
103
|
+
- lib/ios-box/deploy/testflight.rb
|
69
104
|
- lib/ios-box/iosbox.rb
|
70
105
|
- lib/ios-box/tasks.rb
|
71
106
|
- lib/ios-box/tools.rb
|
72
107
|
- lib/ios-box/tools/build.rb
|
108
|
+
- lib/ios-box/tools/config.rb
|
109
|
+
- lib/ios-box/tools/deploy.rb
|
73
110
|
- lib/ios-box/tools/version.rb
|
74
|
-
- lib/ios-box/version.rb
|
75
111
|
- lib/ios_box.rb
|
76
112
|
- spec/build_cache_spec.rb
|
77
113
|
- spec/ios-box_spec.rb
|