fir-cli 1.4.5 → 1.4.6
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/CHANGELOG +5 -0
- data/README.md +2 -1
- data/fir-cli.gemspec +2 -1
- data/lib/fir/cli.rb +6 -1
- data/lib/fir/patches/blank.rb +131 -0
- data/lib/fir/patches/hash.rb +79 -0
- data/lib/fir/patches/instance_variables.rb +30 -0
- data/lib/fir/patches/native_patch.rb +0 -198
- data/lib/fir/patches/try.rb +102 -0
- data/lib/fir/patches.rb +4 -0
- data/lib/fir/util/build_ipa.rb +2 -0
- data/lib/fir/util/http.rb +18 -4
- data/lib/fir/util/publish.rb +7 -4
- data/lib/fir/version.rb +1 -1
- data/test/publish_test.rb +23 -7
- data/test/test_helper.rb +1 -0
- metadata +11 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f230c2c2a1ed0655a63ba484a9a734d9597cf39
|
4
|
+
data.tar.gz: a8f828a4f9cefd0d1c15ccffdc3f389fbd1f5e4a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9baeff6c9a3268ff5cc83f1c955bfbd30f8db989a23ec32395736c14e3a5c8f3f930e36c9ebd49c789cc52236587e36b209f8aa1cd092fc98063a0ec878c5c78
|
7
|
+
data.tar.gz: 721c928eb10bc281fb48ab300597dc27052095ee7048caa67e91beda220d7dd8efeeb9753d109bcded45fbc2440e9fdac2f1dd47d5faa8990b1f27b8ab05ba56
|
data/CHANGELOG
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
## 更新记录
|
2
2
|
|
3
|
+
### fir-cli 1.4.6
|
4
|
+
- 上传增加设置密码及公开访问权限的参数, [Issue #62](https://github.com/FIRHQ/fir-cli/issues/62)
|
5
|
+
- 打包增加指定 `exportProvisioningProfile` 参数, [Issue #59](https://github.com/FIRHQ/fir-cli/issues/59)
|
6
|
+
- 增加 http retry 机制, [Issue #65](https://github.com/FIRHQ/fir-cli/issues/65)
|
7
|
+
|
3
8
|
### fir-cli 1.4.5
|
4
9
|
- 增加 Android flavor 打包(感谢 [msdx](https://github.com/msdx) 的热心帮助)
|
5
10
|
- `$ fir ba <project dir> -f <flavor>`
|
data/README.md
CHANGED
@@ -120,7 +120,7 @@ fir publish 命令可以轻松发布应用到 fir.im, 支持 ipa 和 apk 文件.
|
|
120
120
|
$ fir publish path/to/application -T YOUR_FIR_TOKEN
|
121
121
|
```
|
122
122
|
|
123
|
-
如果需要上传 changelog, 自定义 short 地址, 上传符号表, 生成二维码等功能, 可以使用 `fir publish -h`查看相应的帮助
|
123
|
+
如果需要上传 changelog, 自定义 short 地址, 设置密码, 设置公开访问权限, 上传符号表, 生成二维码等功能, 可以使用 `fir publish -h`查看相应的帮助
|
124
124
|
|
125
125
|
### fir login 使用说明
|
126
126
|
|
@@ -244,3 +244,4 @@ $ fir upgrade
|
|
244
244
|
如果你觉得 fir-cli 对你有所帮助, 欢迎微信打赏支持作者:smile:
|
245
245
|
|
246
246
|

|
247
|
+
|
data/fir-cli.gemspec
CHANGED
@@ -27,7 +27,8 @@ Gem::Specification.new do |spec|
|
|
27
27
|
/_/ /___/_/ |_| \____/_____/___/
|
28
28
|
|
29
29
|
## 更新记录
|
30
|
-
### fir-cli 1.4.
|
30
|
+
### fir-cli 1.4.6
|
31
|
+
- 增加上传时候设置密码及公开访问权限
|
31
32
|
- 增加 Android flavor 打包(感谢 [msdx](https://github.com/msdx) 的热心帮助)
|
32
33
|
- `$ fir ba <project dir> -f <flavor>`
|
33
34
|
- 详细更新记录, 请查看: https://github.com/FIRHQ/fir-cli/blob/master/CHANGELOG
|
data/lib/fir/cli.rb
CHANGED
@@ -20,7 +20,7 @@ module FIR
|
|
20
20
|
|
21
21
|
$ fir bi <project dir> [-c <changelog> -P <bughd project id> -M -p -Q -T <your api token>]
|
22
22
|
|
23
|
-
$ fir bi <git ssh url> [-B develop -c <changelog> -P <bughd project id> -M -p -Q -T <your api token>]
|
23
|
+
$ fir bi <git ssh url> [-B develop -c <changelog> -f <profile> -P <bughd project id> -M -p -Q -T <your api token>]
|
24
24
|
|
25
25
|
$ fir bi <workspace dir> -w -S <scheme name> [-C <configuration>] [-t <target name>] [-o <ipa output dir>] [settings] [-c <changelog>] [-p -Q -T <your api token>]
|
26
26
|
LONGDESC
|
@@ -30,6 +30,7 @@ module FIR
|
|
30
30
|
method_option :scheme, type: :string, aliases: '-S', desc: 'Set the scheme NAME if build workspace'
|
31
31
|
method_option :configuration, type: :string, aliases: '-C', desc: 'Use the build configuration NAME for building each target'
|
32
32
|
method_option :target, type: :string, aliases: '-t', desc: 'Build the target specified by targetname'
|
33
|
+
method_option :profile, type: :string, aliases: '-f', desc: 'Set the export provisioning profile'
|
33
34
|
method_option :output, type: :string, aliases: '-o', desc: 'IPA output path, the default is: BUILD_DIR/fir_build_ipa'
|
34
35
|
method_option :publish, type: :boolean, aliases: '-p', desc: 'true/false if publish to fir.im'
|
35
36
|
method_option :short, type: :string, aliases: '-s', desc: 'Set custom short link if publish to fir.im'
|
@@ -90,11 +91,15 @@ module FIR
|
|
90
91
|
|
91
92
|
$ fir p <app file path> [-c <changelog> -s <custom short link> -Q -T <your api token>]
|
92
93
|
|
94
|
+
$ fir p <app file path> [-c <changelog> -s <custom short link> --password=123456 -o false -Q -T <your api token>]
|
95
|
+
|
93
96
|
$ fir p <app file path> [-c <changelog> -s <custom short link> -m <mapping file path> -P <bughd project id> -Q -T <your api token>]
|
94
97
|
LONGDESC
|
95
98
|
map 'p' => :publish
|
96
99
|
method_option :short, type: :string, aliases: '-s', desc: 'Set custom short link'
|
97
100
|
method_option :changelog, type: :string, aliases: '-c', desc: 'Set changelog'
|
101
|
+
method_option :password, type: :string, aliases: '-p', desc: 'Set password for app'
|
102
|
+
method_option :open, type: :boolean, aliases: '-o', desc: 'true/false if open for everyone, the default is: true', default: true
|
98
103
|
method_option :qrcode, type: :boolean, aliases: '-Q', desc: 'Generate qrcode'
|
99
104
|
method_option :mappingfile, type: :string, aliases: '-m', desc: 'App mapping file'
|
100
105
|
method_option :proj, type: :string, aliases: '-P', desc: 'Project id in BugHD.com if upload app mapping file'
|
@@ -0,0 +1,131 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# An object is blank if it's false, empty, or a whitespace string.
|
5
|
+
# For example, '', ' ', +nil+, [], and {} are all blank.
|
6
|
+
#
|
7
|
+
# This simplifies
|
8
|
+
#
|
9
|
+
# address.nil? || address.empty?
|
10
|
+
#
|
11
|
+
# to
|
12
|
+
#
|
13
|
+
# address.blank?
|
14
|
+
#
|
15
|
+
# @return [true, false]
|
16
|
+
def blank?
|
17
|
+
respond_to?(:empty?) ? !!empty? : !self
|
18
|
+
end
|
19
|
+
|
20
|
+
# An object is present if it's not blank.
|
21
|
+
#
|
22
|
+
# @return [true, false]
|
23
|
+
def present?
|
24
|
+
!blank?
|
25
|
+
end
|
26
|
+
|
27
|
+
# Returns the receiver if it's present otherwise returns +nil+.
|
28
|
+
# <tt>object.presence</tt> is equivalent to
|
29
|
+
#
|
30
|
+
# object.present? ? object : nil
|
31
|
+
#
|
32
|
+
# For example, something like
|
33
|
+
#
|
34
|
+
# state = params[:state] if params[:state].present?
|
35
|
+
# country = params[:country] if params[:country].present?
|
36
|
+
# region = state || country || 'US'
|
37
|
+
#
|
38
|
+
# becomes
|
39
|
+
#
|
40
|
+
# region = params[:state].presence || params[:country].presence || 'US'
|
41
|
+
#
|
42
|
+
# @return [Object]
|
43
|
+
def presence
|
44
|
+
self if present?
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
class NilClass
|
49
|
+
# +nil+ is blank:
|
50
|
+
#
|
51
|
+
# nil.blank? # => true
|
52
|
+
#
|
53
|
+
# @return [true]
|
54
|
+
def blank?
|
55
|
+
true
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
class FalseClass
|
60
|
+
# +false+ is blank:
|
61
|
+
#
|
62
|
+
# false.blank? # => true
|
63
|
+
#
|
64
|
+
# @return [true]
|
65
|
+
def blank?
|
66
|
+
true
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class TrueClass
|
71
|
+
# +true+ is not blank:
|
72
|
+
#
|
73
|
+
# true.blank? # => false
|
74
|
+
#
|
75
|
+
# @return [false]
|
76
|
+
def blank?
|
77
|
+
false
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
class Array
|
82
|
+
# An array is blank if it's empty:
|
83
|
+
#
|
84
|
+
# [].blank? # => true
|
85
|
+
# [1,2,3].blank? # => false
|
86
|
+
#
|
87
|
+
# @return [true, false]
|
88
|
+
alias_method :blank?, :empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
class Hash
|
92
|
+
# A hash is blank if it's empty:
|
93
|
+
#
|
94
|
+
# {}.blank? # => true
|
95
|
+
# { key: 'value' }.blank? # => false
|
96
|
+
#
|
97
|
+
# @return [true, false]
|
98
|
+
alias_method :blank?, :empty?
|
99
|
+
end
|
100
|
+
|
101
|
+
class String
|
102
|
+
BLANK_RE = /\A[[:space:]]*\z/
|
103
|
+
|
104
|
+
# A string is blank if it's empty or contains whitespaces only:
|
105
|
+
#
|
106
|
+
# ''.blank? # => true
|
107
|
+
# ' '.blank? # => true
|
108
|
+
# "\t\n\r".blank? # => true
|
109
|
+
# ' blah '.blank? # => false
|
110
|
+
#
|
111
|
+
# Unicode whitespace is supported:
|
112
|
+
#
|
113
|
+
# "\u00a0".blank? # => true
|
114
|
+
#
|
115
|
+
# @return [true, false]
|
116
|
+
def blank?
|
117
|
+
BLANK_RE === self
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
class Numeric #:nodoc:
|
122
|
+
# No number is blank:
|
123
|
+
#
|
124
|
+
# 1.blank? # => false
|
125
|
+
# 0.blank? # => false
|
126
|
+
#
|
127
|
+
# @return [false]
|
128
|
+
def blank?
|
129
|
+
false
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Hash
|
4
|
+
# Returns a copy of self with all blank keys removed.
|
5
|
+
#
|
6
|
+
# hash = { name: 'Rob', age: '', title: nil }
|
7
|
+
#
|
8
|
+
# hash.compact
|
9
|
+
# # => { name: 'Rob' }
|
10
|
+
def compact
|
11
|
+
delete_if { |_, v| v.is_a?(FalseClass) ? false : v.blank? }
|
12
|
+
end
|
13
|
+
|
14
|
+
# Returns a new hash with all keys converted using the block operation.
|
15
|
+
#
|
16
|
+
# hash = { name: 'Rob', age: '28' }
|
17
|
+
#
|
18
|
+
# hash.transform_keys{ |key| key.to_s.upcase }
|
19
|
+
# # => {"NAME"=>"Rob", "AGE"=>"28"}
|
20
|
+
def transform_keys
|
21
|
+
return enum_for(:transform_keys) unless block_given?
|
22
|
+
result = self.class.new
|
23
|
+
each_key do |key|
|
24
|
+
result[yield(key)] = self[key]
|
25
|
+
end
|
26
|
+
result
|
27
|
+
end
|
28
|
+
|
29
|
+
# Returns a new hash with all keys converted to symbols, as long as
|
30
|
+
# they respond to +to_sym+.
|
31
|
+
#
|
32
|
+
# hash = { 'name' => 'Rob', 'age' => '28' }
|
33
|
+
#
|
34
|
+
# hash.symbolize_keys
|
35
|
+
# # => {:name=>"Rob", :age=>"28"}
|
36
|
+
def symbolize_keys
|
37
|
+
transform_keys { |key| key.to_sym rescue key }
|
38
|
+
end
|
39
|
+
|
40
|
+
# Returns a new hash with all keys converted by the block operation.
|
41
|
+
# This includes the keys from the root hash and from all
|
42
|
+
# nested hashes and arrays.
|
43
|
+
#
|
44
|
+
# hash = { person: { name: 'Rob', age: '28' } }
|
45
|
+
#
|
46
|
+
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
47
|
+
# # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
|
48
|
+
def deep_transform_keys(&block)
|
49
|
+
_deep_transform_keys_in_object(self, &block)
|
50
|
+
end
|
51
|
+
|
52
|
+
# Returns a new hash with all keys converted to symbols, as long as
|
53
|
+
# they respond to +to_sym+. This includes the keys from the root hash
|
54
|
+
# and from all nested hashes and arrays.
|
55
|
+
#
|
56
|
+
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
57
|
+
#
|
58
|
+
# hash.deep_symbolize_keys
|
59
|
+
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
60
|
+
def deep_symbolize_keys
|
61
|
+
deep_transform_keys { |key| key.to_sym rescue key }
|
62
|
+
end
|
63
|
+
|
64
|
+
private
|
65
|
+
|
66
|
+
# support methods for deep transforming nested hashes and arrays
|
67
|
+
def _deep_transform_keys_in_object(object, &block)
|
68
|
+
case object
|
69
|
+
when Hash
|
70
|
+
object.each_with_object({}) do |(key, value), result|
|
71
|
+
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
72
|
+
end
|
73
|
+
when Array
|
74
|
+
object.map { |e| _deep_transform_keys_in_object(e, &block) }
|
75
|
+
else
|
76
|
+
object
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# Returns a hash with string keys that maps instance variable names without "@" to their
|
5
|
+
# corresponding values.
|
6
|
+
#
|
7
|
+
# class C
|
8
|
+
# def initialize(x, y)
|
9
|
+
# @x, @y = x, y
|
10
|
+
# end
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# C.new(0, 1).instance_values # => {"x" => 0, "y" => 1}
|
14
|
+
def instance_values
|
15
|
+
Hash[instance_variables.map { |name| [name[1..-1], instance_variable_get(name)] }]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Returns an array of instance variable names as strings including "@".
|
19
|
+
#
|
20
|
+
# class C
|
21
|
+
# def initialize(x, y)
|
22
|
+
# @x, @y = x, y
|
23
|
+
# end
|
24
|
+
# end
|
25
|
+
#
|
26
|
+
# C.new(0, 1).instance_variable_names # => ["@y", "@x"]
|
27
|
+
def instance_variable_names
|
28
|
+
instance_variables.map { |var| var.to_s }
|
29
|
+
end
|
30
|
+
end
|
@@ -1,203 +1,5 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
-
class Object
|
4
|
-
# An object is blank if it's false, empty, or a whitespace string.
|
5
|
-
# For example, '', ' ', +nil+, [], and {} are all blank.
|
6
|
-
#
|
7
|
-
# This simplifies
|
8
|
-
#
|
9
|
-
# address.nil? || address.empty?
|
10
|
-
#
|
11
|
-
# to
|
12
|
-
#
|
13
|
-
# address.blank?
|
14
|
-
#
|
15
|
-
# @return [true, false]
|
16
|
-
def blank?
|
17
|
-
respond_to?(:empty?) ? empty? : !self
|
18
|
-
end
|
19
|
-
|
20
|
-
# An object is present if it's not blank.
|
21
|
-
#
|
22
|
-
# @return [true, false]
|
23
|
-
def present?
|
24
|
-
!blank?
|
25
|
-
end
|
26
|
-
|
27
|
-
# Returns the receiver if it's present otherwise returns +nil+.
|
28
|
-
# <tt>object.presence</tt> is equivalent to
|
29
|
-
#
|
30
|
-
# object.present? ? object : nil
|
31
|
-
#
|
32
|
-
# For example, something like
|
33
|
-
#
|
34
|
-
# state = params[:state] if params[:state].present?
|
35
|
-
# country = params[:country] if params[:country].present?
|
36
|
-
# region = state || country || 'US'
|
37
|
-
#
|
38
|
-
# becomes
|
39
|
-
#
|
40
|
-
# region = params[:state].presence || params[:country].presence || 'US'
|
41
|
-
#
|
42
|
-
# @return [Object]
|
43
|
-
def presence
|
44
|
-
self if present?
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
class NilClass
|
49
|
-
# +nil+ is blank:
|
50
|
-
#
|
51
|
-
# nil.blank? # => true
|
52
|
-
#
|
53
|
-
# @return [true]
|
54
|
-
def blank?
|
55
|
-
true
|
56
|
-
end
|
57
|
-
end
|
58
|
-
|
59
|
-
class FalseClass
|
60
|
-
# +false+ is blank:
|
61
|
-
#
|
62
|
-
# false.blank? # => true
|
63
|
-
#
|
64
|
-
# @return [true]
|
65
|
-
def blank?
|
66
|
-
true
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
class TrueClass
|
71
|
-
# +true+ is not blank:
|
72
|
-
#
|
73
|
-
# true.blank? # => false
|
74
|
-
#
|
75
|
-
# @return [false]
|
76
|
-
def blank?
|
77
|
-
false
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
class Array
|
82
|
-
# An array is blank if it's empty:
|
83
|
-
#
|
84
|
-
# [].blank? # => true
|
85
|
-
# [1,2,3].blank? # => false
|
86
|
-
#
|
87
|
-
# @return [true, false]
|
88
|
-
alias_method :blank?, :empty?
|
89
|
-
end
|
90
|
-
|
91
|
-
class Hash
|
92
|
-
# A hash is blank if it's empty:
|
93
|
-
#
|
94
|
-
# {}.blank? # => true
|
95
|
-
# { key: 'value' }.blank? # => false
|
96
|
-
#
|
97
|
-
# @return [true, false]
|
98
|
-
alias_method :blank?, :empty?
|
99
|
-
end
|
100
|
-
|
101
|
-
class String
|
102
|
-
BLANK_RE = /\A[[:space:]]*\z/
|
103
|
-
|
104
|
-
# A string is blank if it's empty or contains whitespaces only:
|
105
|
-
#
|
106
|
-
# ''.blank? # => true
|
107
|
-
# ' '.blank? # => true
|
108
|
-
# "\t\n\r".blank? # => true
|
109
|
-
# ' blah '.blank? # => false
|
110
|
-
#
|
111
|
-
# Unicode whitespace is supported:
|
112
|
-
#
|
113
|
-
# "\u00a0".blank? # => true
|
114
|
-
#
|
115
|
-
# @return [true, false]
|
116
|
-
def blank?
|
117
|
-
BLANK_RE === self
|
118
|
-
end
|
119
|
-
end
|
120
|
-
|
121
|
-
class Numeric #:nodoc:
|
122
|
-
# No number is blank:
|
123
|
-
#
|
124
|
-
# 1.blank? # => false
|
125
|
-
# 0.blank? # => false
|
126
|
-
#
|
127
|
-
# @return [false]
|
128
|
-
def blank?
|
129
|
-
false
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
class Hash
|
134
|
-
# Returns a new hash with all keys converted using the block operation.
|
135
|
-
#
|
136
|
-
# hash = { name: 'Rob', age: '28' }
|
137
|
-
#
|
138
|
-
# hash.transform_keys{ |key| key.to_s.upcase }
|
139
|
-
# # => {"NAME"=>"Rob", "AGE"=>"28"}
|
140
|
-
def transform_keys
|
141
|
-
return enum_for(:transform_keys) unless block_given?
|
142
|
-
result = self.class.new
|
143
|
-
each_key do |key|
|
144
|
-
result[yield(key)] = self[key]
|
145
|
-
end
|
146
|
-
result
|
147
|
-
end
|
148
|
-
|
149
|
-
# Returns a new hash with all keys converted to symbols, as long as
|
150
|
-
# they respond to +to_sym+.
|
151
|
-
#
|
152
|
-
# hash = { 'name' => 'Rob', 'age' => '28' }
|
153
|
-
#
|
154
|
-
# hash.symbolize_keys
|
155
|
-
# # => {:name=>"Rob", :age=>"28"}
|
156
|
-
def symbolize_keys
|
157
|
-
transform_keys { |key| key.to_sym rescue key }
|
158
|
-
end
|
159
|
-
|
160
|
-
# Returns a new hash with all keys converted by the block operation.
|
161
|
-
# This includes the keys from the root hash and from all
|
162
|
-
# nested hashes and arrays.
|
163
|
-
#
|
164
|
-
# hash = { person: { name: 'Rob', age: '28' } }
|
165
|
-
#
|
166
|
-
# hash.deep_transform_keys{ |key| key.to_s.upcase }
|
167
|
-
# # => {"PERSON"=>{"NAME"=>"Rob", "AGE"=>"28"}}
|
168
|
-
def deep_transform_keys(&block)
|
169
|
-
_deep_transform_keys_in_object(self, &block)
|
170
|
-
end
|
171
|
-
|
172
|
-
# Returns a new hash with all keys converted to symbols, as long as
|
173
|
-
# they respond to +to_sym+. This includes the keys from the root hash
|
174
|
-
# and from all nested hashes and arrays.
|
175
|
-
#
|
176
|
-
# hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
|
177
|
-
#
|
178
|
-
# hash.deep_symbolize_keys
|
179
|
-
# # => {:person=>{:name=>"Rob", :age=>"28"}}
|
180
|
-
def deep_symbolize_keys
|
181
|
-
deep_transform_keys { |key| key.to_sym rescue key }
|
182
|
-
end
|
183
|
-
|
184
|
-
private
|
185
|
-
|
186
|
-
# support methods for deep transforming nested hashes and arrays
|
187
|
-
def _deep_transform_keys_in_object(object, &block)
|
188
|
-
case object
|
189
|
-
when Hash
|
190
|
-
object.each_with_object({}) do |(key, value), result|
|
191
|
-
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
192
|
-
end
|
193
|
-
when Array
|
194
|
-
object.map { |e| _deep_transform_keys_in_object(e, &block) }
|
195
|
-
else
|
196
|
-
object
|
197
|
-
end
|
198
|
-
end
|
199
|
-
end
|
200
|
-
|
201
3
|
class File
|
202
4
|
class << self
|
203
5
|
# A binary file is Mach-O dSYM
|
@@ -0,0 +1,102 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
class Object
|
4
|
+
# Invokes the public method whose name goes as first argument just like
|
5
|
+
# +public_send+ does, except that if the receiver does not respond to it the
|
6
|
+
# call returns +nil+ rather than raising an exception.
|
7
|
+
#
|
8
|
+
# This method is defined to be able to write
|
9
|
+
#
|
10
|
+
# @person.try(:name)
|
11
|
+
#
|
12
|
+
# instead of
|
13
|
+
#
|
14
|
+
# @person.name if @person
|
15
|
+
#
|
16
|
+
# +try+ calls can be chained:
|
17
|
+
#
|
18
|
+
# @person.try(:spouse).try(:name)
|
19
|
+
#
|
20
|
+
# instead of
|
21
|
+
#
|
22
|
+
# @person.spouse.name if @person && @person.spouse
|
23
|
+
#
|
24
|
+
# +try+ will also return +nil+ if the receiver does not respond to the method:
|
25
|
+
#
|
26
|
+
# @person.try(:non_existing_method) #=> nil
|
27
|
+
#
|
28
|
+
# instead of
|
29
|
+
#
|
30
|
+
# @person.non_existing_method if @person.respond_to?(:non_existing_method) #=> nil
|
31
|
+
#
|
32
|
+
# +try+ returns +nil+ when called on +nil+ regardless of whether it responds
|
33
|
+
# to the method:
|
34
|
+
#
|
35
|
+
# nil.try(:to_i) # => nil, rather than 0
|
36
|
+
#
|
37
|
+
# Arguments and blocks are forwarded to the method if invoked:
|
38
|
+
#
|
39
|
+
# @posts.try(:each_slice, 2) do |a, b|
|
40
|
+
# ...
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# The number of arguments in the signature must match. If the object responds
|
44
|
+
# to the method the call is attempted and +ArgumentError+ is still raised
|
45
|
+
# in case of argument mismatch.
|
46
|
+
#
|
47
|
+
# If +try+ is called without arguments it yields the receiver to a given
|
48
|
+
# block unless it is +nil+:
|
49
|
+
#
|
50
|
+
# @person.try do |p|
|
51
|
+
# ...
|
52
|
+
# end
|
53
|
+
#
|
54
|
+
# You can also call try with a block without accepting an argument, and the block
|
55
|
+
# will be instance_eval'ed instead:
|
56
|
+
#
|
57
|
+
# @person.try { upcase.truncate(50) }
|
58
|
+
#
|
59
|
+
# Please also note that +try+ is defined on +Object+. Therefore, it won't work
|
60
|
+
# with instances of classes that do not have +Object+ among their ancestors,
|
61
|
+
# like direct subclasses of +BasicObject+. For example, using +try+ with
|
62
|
+
# +SimpleDelegator+ will delegate +try+ to the target instead of calling it on
|
63
|
+
# the delegator itself.
|
64
|
+
def try(*a, &b)
|
65
|
+
try!(*a, &b) if a.empty? || respond_to?(a.first)
|
66
|
+
end
|
67
|
+
|
68
|
+
# Same as #try, but will raise a NoMethodError exception if the receiver is not +nil+ and
|
69
|
+
# does not implement the tried method.
|
70
|
+
|
71
|
+
def try!(*a, &b)
|
72
|
+
if a.empty? && block_given?
|
73
|
+
if b.arity.zero?
|
74
|
+
instance_eval(&b)
|
75
|
+
else
|
76
|
+
yield self
|
77
|
+
end
|
78
|
+
else
|
79
|
+
public_send(*a, &b)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class NilClass
|
85
|
+
# Calling +try+ on +nil+ always returns +nil+.
|
86
|
+
# It becomes especially helpful when navigating through associations that may return +nil+.
|
87
|
+
#
|
88
|
+
# nil.try(:name) # => nil
|
89
|
+
#
|
90
|
+
# Without +try+
|
91
|
+
# @person && @person.children.any? && @person.children.first.name
|
92
|
+
#
|
93
|
+
# With +try+
|
94
|
+
# @person.try(:children).try(:first).try(:name)
|
95
|
+
def try(*args)
|
96
|
+
nil
|
97
|
+
end
|
98
|
+
|
99
|
+
def try!(*args)
|
100
|
+
nil
|
101
|
+
end
|
102
|
+
end
|
data/lib/fir/patches.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
|
+
require_relative './patches/blank'
|
3
4
|
require_relative './patches/concern'
|
5
|
+
require_relative './patches/hash'
|
6
|
+
require_relative './patches/instance_variables'
|
4
7
|
require_relative './patches/native_patch'
|
5
8
|
require_relative './patches/os_patch'
|
9
|
+
require_relative './patches/try'
|
data/lib/fir/util/build_ipa.rb
CHANGED
@@ -24,11 +24,13 @@ module FIR
|
|
24
24
|
@configuration = options[:configuration]
|
25
25
|
@target_name = options[:target]
|
26
26
|
@scheme_name = options[:scheme]
|
27
|
+
@profile_name = options[:profile]
|
27
28
|
|
28
29
|
build_cmd = 'xcodebuild build -sdk iphoneos'
|
29
30
|
build_cmd += initialize_xcode_build_path(options)
|
30
31
|
build_cmd += " -configuration '#{@configuration}'" unless @configuration.blank?
|
31
32
|
build_cmd += " -target '#{@target_name}'" unless @target_name.blank?
|
33
|
+
build_cmd += " -exportProvisioningProfile '#{@profile_name}'" unless @profile_name.blank?
|
32
34
|
build_cmd += " #{ipa_custom_settings(args)} 2>&1"
|
33
35
|
build_cmd
|
34
36
|
end
|
data/lib/fir/util/http.rb
CHANGED
@@ -5,6 +5,7 @@ module FIR
|
|
5
5
|
DEFAULT_TIMEOUT = 300
|
6
6
|
|
7
7
|
def get(url, params = {})
|
8
|
+
tries = 5
|
8
9
|
begin
|
9
10
|
res = ::RestClient::Request.execute(
|
10
11
|
method: :get,
|
@@ -13,8 +14,14 @@ module FIR
|
|
13
14
|
headers: default_headers.merge(params: params)
|
14
15
|
)
|
15
16
|
rescue => e
|
16
|
-
logger.error e.message.to_s
|
17
|
-
|
17
|
+
logger.error e.message.to_s
|
18
|
+
if tries > 0
|
19
|
+
logger.info "Retry in #{tries} times......"
|
20
|
+
tries -= 1
|
21
|
+
retry
|
22
|
+
else
|
23
|
+
exit 1
|
24
|
+
end
|
18
25
|
end
|
19
26
|
|
20
27
|
JSON.parse(res.body.force_encoding('UTF-8'), symbolize_names: true)
|
@@ -22,6 +29,7 @@ module FIR
|
|
22
29
|
|
23
30
|
%w(post patch put).each do |method|
|
24
31
|
define_method method do |url, query|
|
32
|
+
tries = 5
|
25
33
|
begin
|
26
34
|
res = ::RestClient::Request.execute(
|
27
35
|
method: method.to_sym,
|
@@ -31,8 +39,14 @@ module FIR
|
|
31
39
|
headers: default_headers
|
32
40
|
)
|
33
41
|
rescue => e
|
34
|
-
logger.error e.message.to_s
|
35
|
-
|
42
|
+
logger.error e.message.to_s
|
43
|
+
if tries > 0
|
44
|
+
logger.info "Retry in #{tries} times......"
|
45
|
+
tries -= 1
|
46
|
+
retry
|
47
|
+
else
|
48
|
+
exit 1
|
49
|
+
end
|
36
50
|
end
|
37
51
|
|
38
52
|
JSON.parse(res.body.force_encoding('UTF-8'), symbolize_names: true)
|
data/lib/fir/util/publish.rb
CHANGED
@@ -102,12 +102,13 @@ module FIR
|
|
102
102
|
end
|
103
103
|
|
104
104
|
def update_app_info
|
105
|
-
|
105
|
+
update_info = { short: @short, passwd: @passwd, is_opened: @is_opened }.compact
|
106
106
|
|
107
|
-
|
107
|
+
return if update_info.blank?
|
108
108
|
|
109
|
-
|
110
|
-
|
109
|
+
logger.info "Updating app info......"
|
110
|
+
|
111
|
+
patch fir_api[:app_url] + "/#{@app_id}", update_info.merge(api_token: @token)
|
111
112
|
end
|
112
113
|
|
113
114
|
def fetch_uploading_info
|
@@ -157,6 +158,8 @@ module FIR
|
|
157
158
|
@token = options[:token] || current_token
|
158
159
|
@changelog = read_changelog(options[:changelog]).to_s.to_utf8
|
159
160
|
@short = options[:short].to_s
|
161
|
+
@passwd = options[:password].to_s
|
162
|
+
@is_opened = !!options[:open]
|
160
163
|
@export_qrcode = !!options[:qrcode]
|
161
164
|
end
|
162
165
|
|
data/lib/fir/version.rb
CHANGED
data/test/publish_test.rb
CHANGED
@@ -2,14 +2,30 @@
|
|
2
2
|
|
3
3
|
class PublishTest < Minitest::Test
|
4
4
|
|
5
|
-
def
|
6
|
-
options = {
|
7
|
-
token:
|
8
|
-
changelog: "test from fir-cli #{Time.now.to_i}"
|
9
|
-
qrcode: true
|
5
|
+
def setup
|
6
|
+
@options = {
|
7
|
+
token: default_token,
|
8
|
+
changelog: "test from fir-cli #{Time.now.to_i}"
|
10
9
|
}
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_simple_publish
|
13
|
+
assert FIR.publish(default_ipa, @options)
|
14
|
+
assert FIR.publish(default_apk, @options)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_update_app_info
|
18
|
+
short = SecureRandom.hex[3..9]
|
19
|
+
passwd = SecureRandom.hex[0..9]
|
20
|
+
is_opened = (rand(100) % 2) == 0
|
21
|
+
|
22
|
+
update_info = { short: short, password: passwd, open: is_opened }
|
23
|
+
FIR.publish(default_ipa, @options.merge(update_info))
|
24
|
+
|
25
|
+
info = FIR.fetch_app_info
|
11
26
|
|
12
|
-
|
13
|
-
|
27
|
+
assert_equal short, info[:short]
|
28
|
+
assert_equal passwd, info[:passwd]
|
29
|
+
assert_equal is_opened, info[:is_opened]
|
14
30
|
end
|
15
31
|
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fir-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NaixSpirit
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-02-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -163,9 +163,13 @@ files:
|
|
163
163
|
- lib/fir/api.yml
|
164
164
|
- lib/fir/cli.rb
|
165
165
|
- lib/fir/patches.rb
|
166
|
+
- lib/fir/patches/blank.rb
|
166
167
|
- lib/fir/patches/concern.rb
|
168
|
+
- lib/fir/patches/hash.rb
|
169
|
+
- lib/fir/patches/instance_variables.rb
|
167
170
|
- lib/fir/patches/native_patch.rb
|
168
171
|
- lib/fir/patches/os_patch.rb
|
172
|
+
- lib/fir/patches/try.rb
|
169
173
|
- lib/fir/util.rb
|
170
174
|
- lib/fir/util/build_apk.rb
|
171
175
|
- lib/fir/util/build_common.rb
|
@@ -202,10 +206,10 @@ metadata: {}
|
|
202
206
|
post_install_message: "\n ______________ ________ ____\n /
|
203
207
|
____/ _/ __ \\ / ____/ / / _/\n / /_ / // /_/ /_____/ / / / /
|
204
208
|
/\n / __/ _/ // _, _/_____/ /___/ /____/ /\n /_/ /___/_/ |_| \\____/_____/___/\n\n
|
205
|
-
\ ## 更新记录\n ### fir-cli 1.4.
|
206
|
-
的热心帮助)\n - `$ fir ba <project dir> -f <flavor>`\n
|
207
|
-
\ - [fir-cli](https://github.com/FIRHQ/fir-cli)
|
208
|
-
request\n "
|
209
|
+
\ ## 更新记录\n ### fir-cli 1.4.6\n - 增加上传时候设置密码及公开访问权限\n - 增加 Android flavor 打包(感谢
|
210
|
+
[msdx](https://github.com/msdx) 的热心帮助)\n - `$ fir ba <project dir> -f <flavor>`\n
|
211
|
+
\ - 详细更新记录, 请查看: https://github.com/FIRHQ/fir-cli/blob/master/CHANGELOG\n - [fir-cli](https://github.com/FIRHQ/fir-cli)
|
212
|
+
已经开源\n - 欢迎 fork, issue 和 pull request\n "
|
209
213
|
rdoc_options: []
|
210
214
|
require_paths:
|
211
215
|
- lib
|
@@ -221,7 +225,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
221
225
|
version: '0'
|
222
226
|
requirements: []
|
223
227
|
rubyforge_project:
|
224
|
-
rubygems_version: 2.4.
|
228
|
+
rubygems_version: 2.4.8
|
225
229
|
signing_key:
|
226
230
|
specification_version: 4
|
227
231
|
summary: fir.im command tool
|