xcode-utils 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +22 -0
- data/README.md +117 -0
- data/bin/xcutils +12 -0
- data/lib/xcutils.rb +6 -0
- data/lib/xcutils/carthage.rb +55 -0
- data/lib/xcutils/carthage/colors.rb +26 -0
- data/lib/xcutils/carthage/xcconfig.rb +198 -0
- data/lib/xcutils/command.rb +14 -0
- data/lib/xcutils/uitest.rb +184 -0
- data/lib/xcutils/version.rb +3 -0
- data/sh/install_carthage.sh +3 -0
- data/sh/remove_unwanted_architectures.sh +30 -0
- data/templates/UITestRunner/Base/UITestAuthorizationProvider.swift +14 -0
- data/templates/UITestRunner/Base/UITestSuite.swift +97 -0
- data/templates/UITestRunner/Suites/MainTestSuite.swift +28 -0
- data/templates/UITestRunner/UITestAuthorizationProviderImpl.swift +27 -0
- data/templates/UITestRunner/UITestRunner.storyboard +26 -0
- data/templates/UITestRunner/UITestRunnerViewController.swift +38 -0
- metadata +156 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: '083f71f7700a515fd77cd99b5ea4637c30108c95f86ac796166049644cd525c0'
|
4
|
+
data.tar.gz: faeace269689e68f1ed160b8728c57f7845ec834d1b87360c120fde34e26bb7a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 4d51d1e3a1a5a21070ac8a899f8f85baf86fa380e67e2cb48b044c90f674c84b61b289b3e139dde65a3e180caaa66e58ebacc7b0baa0a9d1c0ad0dd372b6427c
|
7
|
+
data.tar.gz: 71f167297435f66b9b3d77915b6c3522960b3a497e65fa00bafe97ce80aaa4e9e485f1f47110738fa1150f6fbcaddb84e3a60f0e265a76b8e9ccf0839f152a30
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2020 linecorp
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,117 @@
|
|
1
|
+
# Xcode::Utils
|
2
|
+
|
3
|
+
[![Gem Version](http://img.shields.io/gem/v/xcode-utils.svg?style=flat)](http://badge.fury.io/rb/xcode-utils)
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
```
|
8
|
+
$ gem install xcode-utils
|
9
|
+
```
|
10
|
+
|
11
|
+
## UITestRunner
|
12
|
+
|
13
|
+
### Install UITestRunner in your xcode project
|
14
|
+
```
|
15
|
+
$ cd #{your project root}
|
16
|
+
|
17
|
+
$ xcutils uitest install --project-name="VVID" --target-config="Debug" --target-scheme="VVID Dev"
|
18
|
+
```
|
19
|
+
|
20
|
+
### Xcode configuration has changed automacally
|
21
|
+
|
22
|
+
New Build Configuration and Build Settings
|
23
|
+
|
24
|
+
<img src="img/screenshot_01.png"/>
|
25
|
+
|
26
|
+
<br/>
|
27
|
+
|
28
|
+
New Build Scheme
|
29
|
+
|
30
|
+
<img src="img/screenshot_02.png"/>
|
31
|
+
|
32
|
+
<br/>
|
33
|
+
|
34
|
+
UITestRunner Template
|
35
|
+
|
36
|
+
<img src="img/screenshot_03.png"/>
|
37
|
+
|
38
|
+
### Implement your authorization provider generated
|
39
|
+
``` swift
|
40
|
+
struct UITestAuthorizationProviderImpl: UITestAuthorizationProvider {
|
41
|
+
|
42
|
+
// MARK: - Implementations of Protocol UITestAuthorizationProvider
|
43
|
+
|
44
|
+
var hasAccessToken: Bool {
|
45
|
+
return false
|
46
|
+
}
|
47
|
+
var hasRefreshToken: Bool {
|
48
|
+
return false
|
49
|
+
}
|
50
|
+
|
51
|
+
func refreshToken(completion: @escaping () -> Void) {
|
52
|
+
}
|
53
|
+
|
54
|
+
func signIn(_ parent: UIViewController, completion: @escaping () -> Void) {
|
55
|
+
}
|
56
|
+
|
57
|
+
func signOut() {
|
58
|
+
}
|
59
|
+
}
|
60
|
+
```
|
61
|
+
### Implement your test suite generated
|
62
|
+
``` swift
|
63
|
+
final class MainTestSuite: UITestSuite {
|
64
|
+
|
65
|
+
// MARK: - Implementations of abstraction
|
66
|
+
|
67
|
+
override func setUp() {
|
68
|
+
// Put setup code here. This method is called before the invocation of test suite.
|
69
|
+
}
|
70
|
+
|
71
|
+
override func runTests() {
|
72
|
+
// Put run tests code here. This method is called before the invocation of test suite.
|
73
|
+
testExample()
|
74
|
+
}
|
75
|
+
|
76
|
+
// MARK: - Tests
|
77
|
+
|
78
|
+
private func testExample() {
|
79
|
+
// This is an example of a functional test case.
|
80
|
+
}
|
81
|
+
}
|
82
|
+
```
|
83
|
+
|
84
|
+
## Carthage Wrapper
|
85
|
+
### Execution Flow
|
86
|
+
1. install carthage if it does not exists
|
87
|
+
2. execute carthage command with arguments
|
88
|
+
3. set the xcode config for carthage frameworks
|
89
|
+
```
|
90
|
+
$ xcutils carthage #{command} #{arguments...}
|
91
|
+
|
92
|
+
ex) xcutils carthage update --platform ios
|
93
|
+
```
|
94
|
+
|
95
|
+
### Xcode configuration has changed automacally
|
96
|
+
|
97
|
+
New Build Phases
|
98
|
+
|
99
|
+
<img src="img/screenshot_04.png"/>
|
100
|
+
|
101
|
+
<br/>
|
102
|
+
|
103
|
+
Framework Search Paths
|
104
|
+
|
105
|
+
<img src="img/screenshot_05.png"/>
|
106
|
+
|
107
|
+
|
108
|
+
### Clean
|
109
|
+
```
|
110
|
+
$ xcutils carthage clean
|
111
|
+
```
|
112
|
+
|
113
|
+
## License
|
114
|
+
|
115
|
+
This project is licensed under the terms of the MIT license. See the [LICENSE](LICENSE) file.
|
116
|
+
|
117
|
+
> This project and all fastlane tools are in no way affiliated with Apple Inc or Google. This project is open source under the MIT license, which means you have full access to the source code and can modify it to fit your own needs. All fastlane tools run on your own computer or server, so your credentials or other sensitive information will never leave your own computer. You are responsible for how you use fastlane tools.
|
data/bin/xcutils
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
if $PROGRAM_NAME == __FILE__
|
4
|
+
ENV['BUNDLE_GEMFILE'] = File.expand_path('../../Gemfile', __FILE__)
|
5
|
+
require 'rubygems'
|
6
|
+
require 'bundler/setup'
|
7
|
+
$LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
|
8
|
+
end
|
9
|
+
|
10
|
+
require 'xcutils'
|
11
|
+
|
12
|
+
XcodeUtils::Command.run(ARGV)
|
data/lib/xcutils.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'xcutils/carthage/xcconfig'
|
2
|
+
|
3
|
+
module XcodeUtils
|
4
|
+
class Command
|
5
|
+
class Carthage < Command
|
6
|
+
self.summary = 'Carthage command wrapper.'
|
7
|
+
self.command = 'carthage'
|
8
|
+
|
9
|
+
def self.install_bash_file_path
|
10
|
+
File.expand_path('../../../sh/install_carthage.sh', __FILE__)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.options
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(argv)
|
18
|
+
super
|
19
|
+
@additional_args = argv.remainder!
|
20
|
+
end
|
21
|
+
|
22
|
+
def validate!
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
path = File.expand_path('../../../sh/install_carthage.sh', __FILE__)
|
27
|
+
system("bash #{Carthage::install_bash_file_path}")
|
28
|
+
system("carthage #{@additional_args.join(" ")}")
|
29
|
+
XcodeUtils::Carthage::XcodeConfig.new.run
|
30
|
+
end
|
31
|
+
|
32
|
+
class Clean < Carthage
|
33
|
+
self.summary = 'Cleanup Carthage.'
|
34
|
+
self.arguments = []
|
35
|
+
|
36
|
+
def self.options
|
37
|
+
[]
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(argv)
|
41
|
+
super
|
42
|
+
@additional_args = argv.remainder!
|
43
|
+
end
|
44
|
+
|
45
|
+
def validate!
|
46
|
+
end
|
47
|
+
|
48
|
+
def run
|
49
|
+
XcodeUtils::Carthage::XcodeConfig.new.clean
|
50
|
+
system("rm -rf ./Carthage")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
|
2
|
+
class String
|
3
|
+
def black; "\e[30m#{self}\e[0m" end
|
4
|
+
def red; "\e[31m#{self}\e[0m" end
|
5
|
+
def green; "\e[32m#{self}\e[0m" end
|
6
|
+
def brown; "\e[33m#{self}\e[0m" end
|
7
|
+
def blue; "\e[34m#{self}\e[0m" end
|
8
|
+
def magenta; "\e[35m#{self}\e[0m" end
|
9
|
+
def cyan; "\e[36m#{self}\e[0m" end
|
10
|
+
def gray; "\e[37m#{self}\e[0m" end
|
11
|
+
|
12
|
+
def bg_black; "\e[40m#{self}\e[0m" end
|
13
|
+
def bg_red; "\e[41m#{self}\e[0m" end
|
14
|
+
def bg_green; "\e[42m#{self}\e[0m" end
|
15
|
+
def bg_brown; "\e[43m#{self}\e[0m" end
|
16
|
+
def bg_blue; "\e[44m#{self}\e[0m" end
|
17
|
+
def bg_magenta; "\e[45m#{self}\e[0m" end
|
18
|
+
def bg_cyan; "\e[46m#{self}\e[0m" end
|
19
|
+
def bg_gray; "\e[47m#{self}\e[0m" end
|
20
|
+
|
21
|
+
def bold; "\e[1m#{self}\e[22m" end
|
22
|
+
def italic; "\e[3m#{self}\e[23m" end
|
23
|
+
def underline; "\e[4m#{self}\e[24m" end
|
24
|
+
def blink; "\e[5m#{self}\e[25m" end
|
25
|
+
def reverse_color; "\e[7m#{self}\e[27m" end
|
26
|
+
end
|
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'xcodeproj'
|
2
|
+
require 'xcutils/carthage/colors'
|
3
|
+
|
4
|
+
module XcodeUtils
|
5
|
+
module Carthage
|
6
|
+
class XcodeConfig
|
7
|
+
def initialize
|
8
|
+
@build_path = './Carthage/Build/iOS'
|
9
|
+
@embed_framework_name = 'Embed Carthage Frameworks'
|
10
|
+
@framework_search_paths = '$(PROJECT_DIR)/Carthage/Build/iOS'
|
11
|
+
@remove_unwanted_framework_architectures = 'Remove Unwanted Framework Architectures'
|
12
|
+
@remove_unwanted_framework_architectures_script = get_file_as_string(File.expand_path('../../../../sh/remove_unwanted_architectures.sh', __FILE__))
|
13
|
+
end
|
14
|
+
|
15
|
+
def run
|
16
|
+
open_project
|
17
|
+
begin_xcconfig
|
18
|
+
end
|
19
|
+
|
20
|
+
def clean
|
21
|
+
open_project
|
22
|
+
begin_cleanup
|
23
|
+
end
|
24
|
+
|
25
|
+
def open_project
|
26
|
+
if !Dir.exist?(@build_path)
|
27
|
+
abort("😭 The Carthage build has not yet been successful. Please try again after successful arthage build.")
|
28
|
+
end
|
29
|
+
|
30
|
+
project_names = Dir["./*.xcodeproj"]
|
31
|
+
|
32
|
+
if project_names.first.nil?
|
33
|
+
abort("😭 Does not exist project to configure.")
|
34
|
+
end
|
35
|
+
|
36
|
+
puts "💎💎 Project Found -> #{project_names.first} 💎💎"
|
37
|
+
|
38
|
+
@project = Xcodeproj::Project.open(project_names.first)
|
39
|
+
end
|
40
|
+
|
41
|
+
def begin_cleanup
|
42
|
+
puts "🙏 Start cleanup..".green
|
43
|
+
|
44
|
+
@project.targets.each do |target|
|
45
|
+
puts "👻 Clean target -> #{target.name}"
|
46
|
+
|
47
|
+
exist_build_phase = target.build_phases.find { |build_phase| build_phase.class == Xcodeproj::Project::Object::PBXCopyFilesBuildPhase && build_phase.name == @embed_framework_name }
|
48
|
+
exist_arch_build_phase = target.build_phases.find { |build_phase| build_phase.class == Xcodeproj::Project::Object::PBXShellScriptBuildPhase && build_phase.name == @remove_unwanted_framework_architectures }
|
49
|
+
|
50
|
+
if !exist_build_phase.nil?
|
51
|
+
puts "Delete exist embed carthage framework in build phases".gray
|
52
|
+
exist_build_phase.files_references.each do |reference|
|
53
|
+
reference.remove_from_project
|
54
|
+
end
|
55
|
+
exist_build_phase.clear
|
56
|
+
target.build_phases.delete(exist_build_phase)
|
57
|
+
end
|
58
|
+
|
59
|
+
if !exist_arch_build_phase.nil?
|
60
|
+
puts "Delete exist remove unwanted framework architectures in build phases".gray
|
61
|
+
exist_arch_build_phase.clear
|
62
|
+
target.build_phases.delete(exist_arch_build_phase)
|
63
|
+
end
|
64
|
+
|
65
|
+
target.build_configurations.each do |config|
|
66
|
+
paths = config.build_settings['FRAMEWORK_SEARCH_PATHS']
|
67
|
+
|
68
|
+
if paths.include?(@framework_search_paths)
|
69
|
+
paths.delete(@framework_search_paths)
|
70
|
+
config.build_settings['FRAMEWORK_SEARCH_PATHS'] = paths
|
71
|
+
puts "#{config}: Delete #{@framework_search_paths} in FRAMEWORK_SEARCH_PATHS".gray
|
72
|
+
end
|
73
|
+
end
|
74
|
+
puts "\n"
|
75
|
+
end
|
76
|
+
|
77
|
+
@project.save()
|
78
|
+
|
79
|
+
puts "👌 Finish cleanup".green
|
80
|
+
end
|
81
|
+
|
82
|
+
def begin_xcconfig
|
83
|
+
puts "🙏 Start xcconfig..".green
|
84
|
+
|
85
|
+
new_build_phase = nil
|
86
|
+
new_arch_build_phase = nil
|
87
|
+
|
88
|
+
@project.targets.each do |target|
|
89
|
+
puts "👻 Build target -> #{target.name}"
|
90
|
+
|
91
|
+
exist_build_phase = target.build_phases.find { |build_phase| build_phase.class == Xcodeproj::Project::Object::PBXCopyFilesBuildPhase && build_phase.name == @embed_framework_name }
|
92
|
+
exist_arch_build_phase = target.build_phases.find { |build_phase| build_phase.class == Xcodeproj::Project::Object::PBXShellScriptBuildPhase && build_phase.name == @remove_unwanted_framework_architectures }
|
93
|
+
|
94
|
+
if !exist_build_phase.nil?
|
95
|
+
puts "Delete exist embed carthage framework in build phases".gray
|
96
|
+
exist_build_phase.files_references.each do |reference|
|
97
|
+
reference.remove_from_project
|
98
|
+
end
|
99
|
+
exist_build_phase.clear
|
100
|
+
target.build_phases.delete(exist_build_phase)
|
101
|
+
end
|
102
|
+
|
103
|
+
if new_build_phase.nil?
|
104
|
+
new_build_phase = create_embed_frameworks_build_phase
|
105
|
+
add_embedded_binaries(new_build_phase)
|
106
|
+
puts "Insert new embed carthage framework #{new_build_phase} into build phases".gray
|
107
|
+
end
|
108
|
+
|
109
|
+
if !exist_arch_build_phase.nil?
|
110
|
+
puts "Delete exist remove unwanted framework architectures in build phases".gray
|
111
|
+
exist_arch_build_phase.clear
|
112
|
+
target.build_phases.delete(exist_arch_build_phase)
|
113
|
+
end
|
114
|
+
|
115
|
+
if new_arch_build_phase.nil?
|
116
|
+
new_arch_build_phase = create_shell_script_build_phase(@remove_unwanted_framework_architectures)
|
117
|
+
new_arch_build_phase.shell_script = @remove_unwanted_framework_architectures_script
|
118
|
+
add_input_files(new_arch_build_phase)
|
119
|
+
puts "Insert new remove unwanted framework architectures #{new_arch_build_phase} into build phases".gray
|
120
|
+
end
|
121
|
+
|
122
|
+
target.build_phases << new_build_phase
|
123
|
+
target.build_phases << new_arch_build_phase
|
124
|
+
|
125
|
+
puts "#{target.build_configurations}"
|
126
|
+
|
127
|
+
target.build_configurations.each do |config|
|
128
|
+
paths = config.build_settings['FRAMEWORK_SEARCH_PATHS']
|
129
|
+
|
130
|
+
if !paths.include?(@framework_search_paths)
|
131
|
+
paths << @framework_search_paths
|
132
|
+
config.build_settings['FRAMEWORK_SEARCH_PATHS'] = paths
|
133
|
+
puts "#{config}: Insert #{@framework_search_paths} into FRAMEWORK_SEARCH_PATHS".gray
|
134
|
+
end
|
135
|
+
end
|
136
|
+
puts "\n"
|
137
|
+
end
|
138
|
+
|
139
|
+
@project.save()
|
140
|
+
|
141
|
+
puts "👌 Finish xcconfig".green
|
142
|
+
end
|
143
|
+
|
144
|
+
def get_file_as_string(filename)
|
145
|
+
data = ''
|
146
|
+
f = File.open(filename, "r")
|
147
|
+
f.each_line do |line|
|
148
|
+
data += line
|
149
|
+
end
|
150
|
+
return data
|
151
|
+
end
|
152
|
+
|
153
|
+
def create_embed_frameworks_build_phase
|
154
|
+
build_phase = @project.new(Xcodeproj::Project::Object::PBXCopyFilesBuildPhase)
|
155
|
+
build_phase.name = @embed_framework_name
|
156
|
+
build_phase.symbol_dst_subfolder_spec = :frameworks
|
157
|
+
return build_phase
|
158
|
+
end
|
159
|
+
|
160
|
+
def create_shell_script_build_phase(name)
|
161
|
+
build_phase = @project.new(Xcodeproj::Project::Object::PBXShellScriptBuildPhase)
|
162
|
+
build_phase.name = name
|
163
|
+
return build_phase
|
164
|
+
end
|
165
|
+
|
166
|
+
def add_embedded_binaries(build_phase)
|
167
|
+
input_paths = []
|
168
|
+
Dir.entries(@build_path).each do |entry|
|
169
|
+
matched = /^(.*)\.framework$/.match(entry)
|
170
|
+
|
171
|
+
if !matched.nil?
|
172
|
+
frameworks_group = @project.groups.find { |group| group.display_name == 'Frameworks' }
|
173
|
+
framework_ref = frameworks_group.new_file("Carthage/Build/iOS/#{matched.string}")
|
174
|
+
build_file = build_phase.add_file_reference(framework_ref)
|
175
|
+
build_file.settings = { 'ATTRIBUTES' => ['CodeSignOnCopy', 'RemoveHeadersOnCopy'] }
|
176
|
+
input_paths.push("${SRCROOT}/Carthage/Build/iOS/#{matched.string}")
|
177
|
+
puts "framework_ref -> #{framework_ref}".gray
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def add_input_files(build_phase)
|
183
|
+
input_paths = []
|
184
|
+
|
185
|
+
Dir.entries(@build_path).each do |entry|
|
186
|
+
matched = /^(.*)\.framework$/.match(entry)
|
187
|
+
if !matched.nil?
|
188
|
+
input_paths.push("${SRCROOT}/Carthage/Build/iOS/#{matched.string}")
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
build_phase.input_paths = input_paths
|
193
|
+
|
194
|
+
puts "Add input files to run script -> #{input_paths}".gray
|
195
|
+
end
|
196
|
+
end
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'claide'
|
2
|
+
require 'xcutils/version'
|
3
|
+
|
4
|
+
module XcodeUtils
|
5
|
+
class Command < CLAide::Command
|
6
|
+
require 'xcutils/uitest'
|
7
|
+
require 'xcutils/carthage'
|
8
|
+
|
9
|
+
self.abstract_command = true
|
10
|
+
self.command = 'xcutils'
|
11
|
+
self.version = VERSION
|
12
|
+
self.description = 'Xcode utils.'
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
require 'xcodeproj'
|
2
|
+
require 'plist'
|
3
|
+
require 'nokogiri'
|
4
|
+
|
5
|
+
module XcodeUtils
|
6
|
+
class Command
|
7
|
+
class UITest < Command
|
8
|
+
self.abstract_command = true
|
9
|
+
self.command = 'uitest'
|
10
|
+
|
11
|
+
class Install < UITest
|
12
|
+
self.summary = 'Install uitest.'
|
13
|
+
|
14
|
+
self.arguments = [
|
15
|
+
CLAide::Argument.new('PROJECT_NAME', :true),
|
16
|
+
CLAide::Argument.new('BASE_CONFIG_NAME', :true),
|
17
|
+
CLAide::Argument.new('BASE_SCHEME_NAME', :true)
|
18
|
+
]
|
19
|
+
|
20
|
+
def self.options
|
21
|
+
[
|
22
|
+
['--project-name=""', 'The name of your xcode project'],
|
23
|
+
['--target-config=""', 'The name of build configuration to be copied to uitestrunner build configuration'],
|
24
|
+
['--target-scheme=""', 'The name of build scheme to be copied to uitestrunner build scheme'],
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
def initialize(argv)
|
29
|
+
@project_name = argv.option('project-name', nil)
|
30
|
+
@taget_config = argv.option('target-config', nil)
|
31
|
+
@target_scheme = argv.option('target-scheme', nil)
|
32
|
+
@uitest_name = 'UITestRunner'
|
33
|
+
@project_path = "./#{@project_name}.xcodeproj"
|
34
|
+
super
|
35
|
+
@additional_args = argv.remainder!
|
36
|
+
end
|
37
|
+
|
38
|
+
def validate!
|
39
|
+
super
|
40
|
+
help! 'Argument --project-name is required.' unless @project_name
|
41
|
+
help! 'Argument --target-config is required.' unless @taget_config
|
42
|
+
help! 'Argument --target-scheme is required.' unless @target_scheme
|
43
|
+
end
|
44
|
+
|
45
|
+
def run
|
46
|
+
generate_build_configuration
|
47
|
+
generate_scheme
|
48
|
+
copy_template_files
|
49
|
+
end
|
50
|
+
|
51
|
+
def generate_build_configuration
|
52
|
+
puts "Input: project_name: #{@project_name}, target_config: #{@taget_config}, target_scheme: #{@target_scheme}"
|
53
|
+
|
54
|
+
project = Xcodeproj::Project.open(@project_path)
|
55
|
+
configuration_list = project.root_object.build_configuration_list
|
56
|
+
|
57
|
+
if configuration_list.build_settings(@uitest_name) != nil
|
58
|
+
puts "uitest already install in the project #{@project_name}"
|
59
|
+
return
|
60
|
+
end
|
61
|
+
|
62
|
+
puts "Initializing #{@uitest_name}"
|
63
|
+
puts "Generating project configuration"
|
64
|
+
|
65
|
+
configuration = project.new(Xcodeproj::Project::Object::XCBuildConfiguration)
|
66
|
+
configuration.name = @uitest_name
|
67
|
+
configuration.build_settings = configuration_list.build_settings(@taget_config)
|
68
|
+
configuration_list.build_configurations << configuration
|
69
|
+
|
70
|
+
project.targets.each do |target|
|
71
|
+
break if target.build_configurations.select { |e| e.name == @uitest_name }.count > 0
|
72
|
+
|
73
|
+
puts "Generating build configuration #{target.name}:#{@uitest_name}"
|
74
|
+
|
75
|
+
base_config = target.build_configurations.select { |e| e.name == @taget_config }.first
|
76
|
+
org_main_storyboard_file = nil
|
77
|
+
|
78
|
+
target.build_configurations.each { |e|
|
79
|
+
path = e.build_settings['INFOPLIST_FILE']
|
80
|
+
obj = Plist.parse_xml(path)
|
81
|
+
var_name = '$(MAIN_STORYBOARD_FILE)'
|
82
|
+
e.build_settings['MAIN_STORYBOARD_FILE'] = obj['UIMainStoryboardFile'] != var_name ? obj['UIMainStoryboardFile'] : org_main_storyboard_file
|
83
|
+
obj['UIMainStoryboardFile'] = '$(MAIN_STORYBOARD_FILE)'
|
84
|
+
|
85
|
+
if org_main_storyboard_file == nil
|
86
|
+
org_main_storyboard_file = e.build_settings['MAIN_STORYBOARD_FILE']
|
87
|
+
end
|
88
|
+
|
89
|
+
File.write(path, obj.to_plist)
|
90
|
+
}
|
91
|
+
|
92
|
+
new_config = project.new(Xcodeproj::Project::Object::XCBuildConfiguration)
|
93
|
+
new_config.name = @uitest_name
|
94
|
+
new_config.base_configuration_reference = base_config.base_configuration_reference
|
95
|
+
new_config.build_settings.update(base_config.build_settings)
|
96
|
+
new_config.build_settings['MAIN_STORYBOARD_FILE'] = @uitest_name
|
97
|
+
|
98
|
+
target.build_configurations << new_config
|
99
|
+
|
100
|
+
puts "Generating scheme #{target.name} #{@uitest_name}"
|
101
|
+
|
102
|
+
project.save()
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
def generate_scheme
|
107
|
+
scheme_name = "#{@project_name} #{@uitest_name}"
|
108
|
+
|
109
|
+
FileUtils.copy_file(scheme_path(@target_scheme), scheme_path(scheme_name))
|
110
|
+
|
111
|
+
scheme = Xcodeproj::XCScheme.new(scheme_path(scheme_name))
|
112
|
+
scheme.launch_action.build_configuration = @uitest_name
|
113
|
+
scheme.save_as(@project_path, scheme_name)
|
114
|
+
end
|
115
|
+
|
116
|
+
def copy_template_files
|
117
|
+
template_path = "./#{@project_name}/#{@uitest_name}"
|
118
|
+
|
119
|
+
if Dir.exist?(template_path)
|
120
|
+
puts "Template files already exist in the project #{@project_name}"
|
121
|
+
return
|
122
|
+
end
|
123
|
+
|
124
|
+
puts "Copying template files into project #{@project_name}"
|
125
|
+
|
126
|
+
path = File.expand_path('../../../templates', __FILE__)
|
127
|
+
FileUtils.copy_entry path, "./#{@project_name}"
|
128
|
+
|
129
|
+
puts "Adding references for files and resources into project #{@project_name}"
|
130
|
+
|
131
|
+
project = Xcodeproj::Project.open(@project_path)
|
132
|
+
|
133
|
+
project.targets.each { |target|
|
134
|
+
target_group = project.groups.select { |e| e.path == target.name }.first
|
135
|
+
template_group = target_group.new_group(nil, @uitest_name)
|
136
|
+
add_files("#{template_path}/*", template_group, target)
|
137
|
+
}
|
138
|
+
|
139
|
+
project.save()
|
140
|
+
end
|
141
|
+
|
142
|
+
def add_files(direc, current_group, main_target)
|
143
|
+
Dir.glob(direc) do |item|
|
144
|
+
next if item == '.' or item == '.DS_Store'
|
145
|
+
if File.directory?(item)
|
146
|
+
group_name = File.basename(item)
|
147
|
+
created_group = current_group.new_group(nil, group_name)
|
148
|
+
add_files("#{item}/*", created_group, main_target)
|
149
|
+
else
|
150
|
+
i = current_group.new_file(File.basename(item))
|
151
|
+
|
152
|
+
if item.include? ".swift" or item.include? ".m"
|
153
|
+
main_target.add_file_references([i])
|
154
|
+
end
|
155
|
+
|
156
|
+
if item.include? ".storyboard" or item.include? ".xib"
|
157
|
+
set_custom_module(item)
|
158
|
+
main_target.add_resources([i])
|
159
|
+
end
|
160
|
+
end
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def set_custom_module(item)
|
165
|
+
doc = Nokogiri::XML(File.open(item))
|
166
|
+
nodes = doc.xpath("//viewController")
|
167
|
+
|
168
|
+
nodes.each { |e|
|
169
|
+
e['customModule'] = @project_name
|
170
|
+
}
|
171
|
+
|
172
|
+
if nodes.count > 0
|
173
|
+
File.write(item, doc.to_xml)
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
def scheme_path(name)
|
178
|
+
return "#{@project_path}/xcshareddata/xcschemes/#{name}.xcscheme"
|
179
|
+
end
|
180
|
+
|
181
|
+
end
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
if [ "${CONFIGURATION}" = "Release" ]; then
|
2
|
+
APP_PATH="${TARGET_BUILD_DIR}/${WRAPPER_NAME}"
|
3
|
+
|
4
|
+
# This script loops through the frameworks embedded in the application and
|
5
|
+
# removes unused architectures.
|
6
|
+
find "$APP_PATH" -name \'*.framework\' -type d | while read -r FRAMEWORK
|
7
|
+
do
|
8
|
+
FRAMEWORK_EXECUTABLE_NAME=$(defaults read "$FRAMEWORK/Info.plist" CFBundleExecutable)
|
9
|
+
FRAMEWORK_EXECUTABLE_PATH="$FRAMEWORK/$FRAMEWORK_EXECUTABLE_NAME"
|
10
|
+
echo "Executable is $FRAMEWORK_EXECUTABLE_PATH"
|
11
|
+
|
12
|
+
EXTRACTED_ARCHS=()
|
13
|
+
|
14
|
+
for ARCH in $ARCHS
|
15
|
+
do
|
16
|
+
echo "Extracting $ARCH from $FRAMEWORK_EXECUTABLE_NAME"
|
17
|
+
lipo -extract "$ARCH" "$FRAMEWORK_EXECUTABLE_PATH" -o "$FRAMEWORK_EXECUTABLE_PATH-$ARCH"
|
18
|
+
EXTRACTED_ARCHS+=("$FRAMEWORK_EXECUTABLE_PATH-$ARCH")
|
19
|
+
done
|
20
|
+
|
21
|
+
echo "Merging extracted architectures: ${ARCHS}"
|
22
|
+
lipo -o "$FRAMEWORK_EXECUTABLE_PATH-merged" -create "${EXTRACTED_ARCHS[@]}"
|
23
|
+
rm "${EXTRACTED_ARCHS[@]}"
|
24
|
+
|
25
|
+
echo "Replacing original executable with thinned version"
|
26
|
+
rm "$FRAMEWORK_EXECUTABLE_PATH"
|
27
|
+
mv "$FRAMEWORK_EXECUTABLE_PATH-merged" "$FRAMEWORK_EXECUTABLE_PATH"
|
28
|
+
|
29
|
+
done
|
30
|
+
fi
|
@@ -0,0 +1,14 @@
|
|
1
|
+
//
|
2
|
+
// UITestAuthorizationProvider.swift
|
3
|
+
// Copyright © 2020 abc-studio. All rights reserved.
|
4
|
+
//
|
5
|
+
|
6
|
+
#if DEBUG
|
7
|
+
protocol UITestAuthorizationProvider {
|
8
|
+
var hasAccessToken: Bool {get}
|
9
|
+
var hasRefreshToken: Bool {get}
|
10
|
+
func refreshToken(completion: @escaping () -> Void)
|
11
|
+
func signIn(_ parent: UIViewController, completion: @escaping () -> Void)
|
12
|
+
func signOut()
|
13
|
+
}
|
14
|
+
#endif
|
@@ -0,0 +1,97 @@
|
|
1
|
+
//
|
2
|
+
// UITestSuite.swift
|
3
|
+
// Copyright © 2020 abc-studio. All rights reserved.
|
4
|
+
//
|
5
|
+
|
6
|
+
#if DEBUG
|
7
|
+
import Foundation
|
8
|
+
|
9
|
+
protocol UITestSuiteInitializable {
|
10
|
+
init()
|
11
|
+
}
|
12
|
+
|
13
|
+
class UITestSuite: UITestSuiteInitializable {
|
14
|
+
|
15
|
+
// MARK: - Implementations of Protocol UITestSuiteInitializable
|
16
|
+
|
17
|
+
required init() {}
|
18
|
+
|
19
|
+
// MARK: - Internal Properties
|
20
|
+
|
21
|
+
static var authorizationProvider: UITestAuthorizationProvider?
|
22
|
+
|
23
|
+
var isNewSession = false
|
24
|
+
var useLogin = true
|
25
|
+
var testRunnerViewController: UITestRunnerViewController! {
|
26
|
+
didSet {
|
27
|
+
setUp()
|
28
|
+
}
|
29
|
+
}
|
30
|
+
var view: UIView {
|
31
|
+
return testRunnerViewController.view
|
32
|
+
}
|
33
|
+
|
34
|
+
// MARK: - Private Properties
|
35
|
+
|
36
|
+
private lazy var strongReferences = [Any]()
|
37
|
+
|
38
|
+
// MARK: - Abstract Methods
|
39
|
+
|
40
|
+
func setUp() {
|
41
|
+
fatalError("setUp has not been implemented")
|
42
|
+
}
|
43
|
+
|
44
|
+
func runTests() {
|
45
|
+
fatalError("runTests has not been implemented")
|
46
|
+
}
|
47
|
+
|
48
|
+
// MARK: - Internal Methods
|
49
|
+
|
50
|
+
func run() {
|
51
|
+
guard useLogin else {
|
52
|
+
logout()
|
53
|
+
runTests()
|
54
|
+
return
|
55
|
+
}
|
56
|
+
guard Self.authorizationProvider?.hasAccessToken == true else {
|
57
|
+
signIn()
|
58
|
+
return
|
59
|
+
}
|
60
|
+
|
61
|
+
if isNewSession || Self.authorizationProvider?.hasRefreshToken == false {
|
62
|
+
logout()
|
63
|
+
signIn()
|
64
|
+
} else {
|
65
|
+
Self.authorizationProvider?.refreshAccessToken {
|
66
|
+
self.runTests()
|
67
|
+
}
|
68
|
+
}
|
69
|
+
}
|
70
|
+
|
71
|
+
func setAsStrongReference(_ any: Any) {
|
72
|
+
strongReferences.append(any)
|
73
|
+
}
|
74
|
+
|
75
|
+
// MARK: - Private Methods
|
76
|
+
|
77
|
+
private func signIn() {
|
78
|
+
Self.authorizationProvider?.signIn(testRunnerViewController) {
|
79
|
+
self.runTests()
|
80
|
+
}
|
81
|
+
}
|
82
|
+
|
83
|
+
private func logout() {
|
84
|
+
Self.authorizationProvider?.signOut()
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
extension UITestSuite {
|
89
|
+
@discardableResult
|
90
|
+
func present(_ viewController: UIViewController, completion: (() -> Void)? = nil) -> UINavigationController {
|
91
|
+
let navigationController = UINavigationController(rootViewController: viewController)
|
92
|
+
navigationController.modalPresentationStyle = .fullScreen
|
93
|
+
testRunnerViewController.present(navigationController, animated: false, completion: completion)
|
94
|
+
return navigationController
|
95
|
+
}
|
96
|
+
}
|
97
|
+
#endif
|
@@ -0,0 +1,28 @@
|
|
1
|
+
//
|
2
|
+
// MainTestSuite.swift
|
3
|
+
// Copyright © 2020 abc-studio. All rights reserved.
|
4
|
+
//
|
5
|
+
|
6
|
+
#if DEBUG
|
7
|
+
import Foundation
|
8
|
+
|
9
|
+
final class MainTestSuite: UITestSuite {
|
10
|
+
|
11
|
+
// MARK: - Implementations of abstraction
|
12
|
+
|
13
|
+
override func setUp() {
|
14
|
+
// Put setup code here. This method is called before the invocation of test suite.
|
15
|
+
}
|
16
|
+
|
17
|
+
override func runTests() {
|
18
|
+
// Put run tests code here. This method is called before the invocation of test suite.
|
19
|
+
testExample()
|
20
|
+
}
|
21
|
+
|
22
|
+
// MARK: - Tests
|
23
|
+
|
24
|
+
private func testExample() {
|
25
|
+
// This is an example of a functional test case.
|
26
|
+
}
|
27
|
+
}
|
28
|
+
#endif
|
@@ -0,0 +1,27 @@
|
|
1
|
+
//
|
2
|
+
// UITestAuthorizationProviderImpl.swift
|
3
|
+
// Copyright © 2020 abc-studio. All rights reserved.
|
4
|
+
//
|
5
|
+
|
6
|
+
#if DEBUG
|
7
|
+
struct UITestAuthorizationProviderImpl: UITestAuthorizationProvider {
|
8
|
+
|
9
|
+
// MARK: - Implementations of Protocol UITestAuthorizationProvider
|
10
|
+
|
11
|
+
var hasAccessToken: Bool {
|
12
|
+
return false
|
13
|
+
}
|
14
|
+
var hasRefreshToken: Bool {
|
15
|
+
return false
|
16
|
+
}
|
17
|
+
|
18
|
+
func refreshToken(completion: @escaping () -> Void) {
|
19
|
+
}
|
20
|
+
|
21
|
+
func signIn(_ parent: UIViewController, completion: @escaping () -> Void) {
|
22
|
+
}
|
23
|
+
|
24
|
+
func signOut() {
|
25
|
+
}
|
26
|
+
}
|
27
|
+
#endif
|
@@ -0,0 +1,26 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16097.2" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="SCr-6D-ZxU">
|
3
|
+
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
4
|
+
<dependencies>
|
5
|
+
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
|
6
|
+
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
7
|
+
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
8
|
+
</dependencies>
|
9
|
+
<scenes>
|
10
|
+
<!--Test Runner View Controller-->
|
11
|
+
<scene sceneID="Qdh-9A-DFL">
|
12
|
+
<objects>
|
13
|
+
<viewController id="SCr-6D-ZxU" customClass="UITestRunnerViewController" customModule="" customModuleProvider="target" sceneMemberID="viewController">
|
14
|
+
<view key="view" contentMode="scaleToFill" id="TAc-ms-UKq">
|
15
|
+
<rect key="frame" x="0.0" y="0.0" width="414" height="896"/>
|
16
|
+
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
17
|
+
<color key="backgroundColor" systemColor="systemBackgroundColor" cocoaTouchSystemColor="whiteColor"/>
|
18
|
+
<viewLayoutGuide key="safeArea" id="TVl-0y-oBG"/>
|
19
|
+
</view>
|
20
|
+
</viewController>
|
21
|
+
<placeholder placeholderIdentifier="IBFirstResponder" id="Kxe-uh-kQb" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
|
22
|
+
</objects>
|
23
|
+
<point key="canvasLocation" x="-129" y="20"/>
|
24
|
+
</scene>
|
25
|
+
</scenes>
|
26
|
+
</document>
|
@@ -0,0 +1,38 @@
|
|
1
|
+
//
|
2
|
+
// UITestRunnerViewController.swift
|
3
|
+
// Copyright © 2020 abc-studio. All rights reserved.
|
4
|
+
//
|
5
|
+
|
6
|
+
#if DEBUG
|
7
|
+
import UIKit
|
8
|
+
|
9
|
+
final class UITestRunnerViewController: UIViewController {
|
10
|
+
|
11
|
+
// MARK: - Overridden: UIViewController
|
12
|
+
|
13
|
+
override func viewDidLoad() {
|
14
|
+
super.viewDidLoad()
|
15
|
+
|
16
|
+
title = "UITestRunner"
|
17
|
+
|
18
|
+
UITestSuite.authorizationProvider = UITestAuthorizationProviderImpl()
|
19
|
+
|
20
|
+
runTestSuites()
|
21
|
+
}
|
22
|
+
|
23
|
+
// MARK: - Private Properties
|
24
|
+
|
25
|
+
private var suite: UITestSuite!
|
26
|
+
|
27
|
+
// MARK: - Private Methods
|
28
|
+
|
29
|
+
private func runTestSuites() {
|
30
|
+
runTestSuite(MainTestSuite.self)
|
31
|
+
}
|
32
|
+
private func runTestSuite<T: UITestSuite>(_ suiteType: T.Type) {
|
33
|
+
suite = suiteType.init()
|
34
|
+
suite.testRunnerViewController = self
|
35
|
+
suite.run()
|
36
|
+
}
|
37
|
+
}
|
38
|
+
#endif
|
metadata
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: xcode-utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Steve Kim
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2020-08-17 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: claide
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.9.1
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: 1.1.0
|
23
|
+
type: :development
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.1
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.1.0
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: xcodeproj
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: 1.18.0
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '2.0'
|
43
|
+
type: :development
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 1.18.0
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '2.0'
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: plist
|
55
|
+
requirement: !ruby/object:Gem::Requirement
|
56
|
+
requirements:
|
57
|
+
- - ">="
|
58
|
+
- !ruby/object:Gem::Version
|
59
|
+
version: 3.5.0
|
60
|
+
- - "<"
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '4.0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: 3.5.0
|
70
|
+
- - "<"
|
71
|
+
- !ruby/object:Gem::Version
|
72
|
+
version: '4.0'
|
73
|
+
- !ruby/object:Gem::Dependency
|
74
|
+
name: nokogiri
|
75
|
+
requirement: !ruby/object:Gem::Requirement
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: 1.10.10
|
80
|
+
- - "<"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '2.0'
|
83
|
+
type: :development
|
84
|
+
prerelease: false
|
85
|
+
version_requirements: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: 1.10.10
|
90
|
+
- - "<"
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '2.0'
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: bundler
|
95
|
+
requirement: !ruby/object:Gem::Requirement
|
96
|
+
requirements:
|
97
|
+
- - "~>"
|
98
|
+
- !ruby/object:Gem::Version
|
99
|
+
version: '1.7'
|
100
|
+
type: :development
|
101
|
+
prerelease: false
|
102
|
+
version_requirements: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - "~>"
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '1.7'
|
107
|
+
description: Xcode utils provides uitest and carthage proxy
|
108
|
+
email:
|
109
|
+
- pisces@linecorp.com
|
110
|
+
executables:
|
111
|
+
- xcutils
|
112
|
+
extensions: []
|
113
|
+
extra_rdoc_files: []
|
114
|
+
files:
|
115
|
+
- LICENSE
|
116
|
+
- README.md
|
117
|
+
- bin/xcutils
|
118
|
+
- lib/xcutils.rb
|
119
|
+
- lib/xcutils/carthage.rb
|
120
|
+
- lib/xcutils/carthage/colors.rb
|
121
|
+
- lib/xcutils/carthage/xcconfig.rb
|
122
|
+
- lib/xcutils/command.rb
|
123
|
+
- lib/xcutils/uitest.rb
|
124
|
+
- lib/xcutils/version.rb
|
125
|
+
- sh/install_carthage.sh
|
126
|
+
- sh/remove_unwanted_architectures.sh
|
127
|
+
- templates/UITestRunner/Base/UITestAuthorizationProvider.swift
|
128
|
+
- templates/UITestRunner/Base/UITestSuite.swift
|
129
|
+
- templates/UITestRunner/Suites/MainTestSuite.swift
|
130
|
+
- templates/UITestRunner/UITestAuthorizationProviderImpl.swift
|
131
|
+
- templates/UITestRunner/UITestRunner.storyboard
|
132
|
+
- templates/UITestRunner/UITestRunnerViewController.swift
|
133
|
+
homepage: https://git.linecorp.com/abc/xcode-utils.git
|
134
|
+
licenses:
|
135
|
+
- MIT
|
136
|
+
metadata: {}
|
137
|
+
post_install_message:
|
138
|
+
rdoc_options: []
|
139
|
+
require_paths:
|
140
|
+
- lib
|
141
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - ">="
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: 2.0.0
|
146
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
147
|
+
requirements:
|
148
|
+
- - ">="
|
149
|
+
- !ruby/object:Gem::Version
|
150
|
+
version: '0'
|
151
|
+
requirements: []
|
152
|
+
rubygems_version: 3.0.3
|
153
|
+
signing_key:
|
154
|
+
specification_version: 4
|
155
|
+
summary: Xcode utils
|
156
|
+
test_files: []
|