fir-cli-x 1.7.2.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.
Files changed (68) hide show
  1. checksums.yaml +7 -0
  2. data/.codeclimate.yml +8 -0
  3. data/.dockerignore +2 -0
  4. data/.flow-plugin.yml +14 -0
  5. data/.gitignore +27 -0
  6. data/.travis.yml +23 -0
  7. data/CHANGELOG +194 -0
  8. data/Dockerfile +12 -0
  9. data/Gemfile +10 -0
  10. data/LICENSE.txt +22 -0
  11. data/README.md +63 -0
  12. data/Rakefile +10 -0
  13. data/bin/console +11 -0
  14. data/bin/fir +14 -0
  15. data/bin/setup +7 -0
  16. data/doc/help.md +34 -0
  17. data/doc/info.md +44 -0
  18. data/doc/install.md +67 -0
  19. data/doc/login.md +19 -0
  20. data/doc/publish.md +35 -0
  21. data/doc/upgrade.md +7 -0
  22. data/fir-cli.gemspec +52 -0
  23. data/fir.sh +46 -0
  24. data/install.sh +210 -0
  25. data/lib/fir-cli.rb +3 -0
  26. data/lib/fir.rb +28 -0
  27. data/lib/fir/api.yml +7 -0
  28. data/lib/fir/cli.rb +181 -0
  29. data/lib/fir/patches.rb +10 -0
  30. data/lib/fir/patches/blank.rb +131 -0
  31. data/lib/fir/patches/concern.rb +146 -0
  32. data/lib/fir/patches/default_headers.rb +9 -0
  33. data/lib/fir/patches/hash.rb +79 -0
  34. data/lib/fir/patches/instance_variables.rb +30 -0
  35. data/lib/fir/patches/native_patch.rb +28 -0
  36. data/lib/fir/patches/os_patch.rb +28 -0
  37. data/lib/fir/patches/try.rb +102 -0
  38. data/lib/fir/util.rb +86 -0
  39. data/lib/fir/util/build_apk.rb +77 -0
  40. data/lib/fir/util/build_common.rb +93 -0
  41. data/lib/fir/util/build_ipa.rb +11 -0
  42. data/lib/fir/util/config.rb +43 -0
  43. data/lib/fir/util/http.rb +23 -0
  44. data/lib/fir/util/info.rb +38 -0
  45. data/lib/fir/util/login.rb +17 -0
  46. data/lib/fir/util/mapping.rb +98 -0
  47. data/lib/fir/util/me.rb +19 -0
  48. data/lib/fir/util/parser/apk.rb +46 -0
  49. data/lib/fir/util/parser/bin/pngcrush +0 -0
  50. data/lib/fir/util/parser/common.rb +24 -0
  51. data/lib/fir/util/parser/ipa.rb +188 -0
  52. data/lib/fir/util/parser/pngcrush.rb +23 -0
  53. data/lib/fir/util/publish.rb +253 -0
  54. data/lib/fir/version.rb +5 -0
  55. data/lib/fir/xcode_wrapper.sh +29 -0
  56. data/lib/fir_cli.rb +3 -0
  57. data/test/build_ipa_test.rb +17 -0
  58. data/test/cases/test_apk.apk +0 -0
  59. data/test/cases/test_apk_txt +1 -0
  60. data/test/cases/test_ipa.ipa +0 -0
  61. data/test/cases/test_ipa_dsym +0 -0
  62. data/test/info_test.rb +36 -0
  63. data/test/login_test.rb +12 -0
  64. data/test/mapping_test.rb +18 -0
  65. data/test/me_test.rb +17 -0
  66. data/test/publish_test.rb +44 -0
  67. data/test/test_helper.rb +98 -0
  68. metadata +273 -0
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ module RestClient
4
+ class Request
5
+ def default_headers
6
+ { source: 'fir-cli', version: FIR::VERSION }
7
+ end
8
+ end
9
+ 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
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ class File
4
+ class << self
5
+ # A binary file is Mach-O dSYM
6
+ #
7
+ # @return [true, false]
8
+ def dsym?(file_path)
9
+ !(`file -b #{file_path}` =~ /dSYM/).nil?
10
+ end
11
+
12
+ # A file is ASCII text
13
+ #
14
+ # @return [true, false]
15
+ def text?(file_path)
16
+ !(`file -b #{file_path}` =~ /text/).nil?
17
+ end
18
+ end
19
+ end
20
+
21
+ class String
22
+ # Convert String encoding to UTF-8
23
+ #
24
+ # @return string
25
+ def to_utf8
26
+ encode(Encoding.find('UTF-8'), invalid: :replace, undef: :replace, replace: '')
27
+ end
28
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: utf-8
2
+
3
+ module OS
4
+ class << self
5
+
6
+ def windows?
7
+ !(/cygwin|mswin|mingw|bccwin|wince|emx/ =~ RUBY_PLATFORM).nil?
8
+ end
9
+
10
+ def mac?
11
+ !(/darwin/ =~ RUBY_PLATFORM).nil?
12
+ end
13
+
14
+ def unix?
15
+ !OS.windows?
16
+ end
17
+
18
+ def linux?
19
+ OS.unix? && !OS.mac?
20
+ end
21
+
22
+ def set_locale
23
+ system 'export LC_ALL=en_US.UTF-8'
24
+ system 'export LC_CTYPE=en_US.UTF-8'
25
+ system 'export LANG=en_US.UTF-8'
26
+ end
27
+ end
28
+ end
@@ -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/util.rb ADDED
@@ -0,0 +1,86 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative './util/http'
4
+ require_relative './util/config'
5
+ require_relative './util/parser/apk'
6
+ require_relative './util/parser/ipa'
7
+ require_relative './util/parser/pngcrush'
8
+ require_relative './util/login'
9
+ require_relative './util/me'
10
+ require_relative './util/info'
11
+ require_relative './util/build_common'
12
+ require_relative './util/build_ipa'
13
+ require_relative './util/build_apk'
14
+ require_relative './util/publish'
15
+ require_relative './util/mapping'
16
+
17
+ module FIR
18
+ module Util
19
+ extend ActiveSupport::Concern
20
+
21
+ module ClassMethods
22
+ include FIR::Http
23
+ include FIR::Config
24
+ include FIR::Login
25
+ include FIR::Me
26
+ include FIR::Info
27
+ include FIR::BuildCommon
28
+ include FIR::BuildIpa
29
+ include FIR::BuildApk
30
+ include FIR::Publish
31
+ include FIR::Mapping
32
+
33
+ attr_accessor :logger
34
+
35
+ def fetch_user_info(token)
36
+ get fir_api[:user_url], api_token: token
37
+ end
38
+
39
+ def fetch_user_uuid(token)
40
+ user_info = fetch_user_info(token)
41
+ user_info[:uuid]
42
+ end
43
+
44
+ def check_file_exist(path)
45
+ return if File.file?(path)
46
+
47
+ logger.error 'File does not exist'
48
+ exit 1
49
+ end
50
+
51
+ def check_supported_file(path)
52
+ return if APP_FILE_TYPE.include?(File.extname(path))
53
+
54
+ logger.error 'Unsupported file type'
55
+ exit 1
56
+ end
57
+
58
+ def check_token_cannot_be_blank(token)
59
+ return unless token.blank?
60
+
61
+ logger.error 'Token can not be blank'
62
+ end
63
+
64
+ def check_logined
65
+ return unless current_token.blank?
66
+
67
+ logger.error 'Please use `fir login` first'
68
+ exit 1
69
+ end
70
+
71
+ def logger_info_blank_line
72
+ logger.info ''
73
+ end
74
+
75
+ def logger_info_dividing_line
76
+ logger.info '✈ -------------------------------------------- ✈'
77
+ end
78
+
79
+ def generate_rqrcode(string, png_file_path)
80
+ qrcode = ::RQRCode::QRCode.new(string.to_s)
81
+ qrcode.as_png(size: 500, border_modules: 2, file: png_file_path)
82
+ png_file_path
83
+ end
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,77 @@
1
+ # encoding: utf-8
2
+
3
+ module FIR
4
+ module BuildApk
5
+
6
+ def build_apk(*args, options)
7
+ logger.warn "build 在 fir-cli 即将过期, 推荐使用 gradlew 打包 apk文件后 后再使用 fir 工具上传生成的apk 文件"
8
+ initialize_build_common_options(args, options)
9
+ set_flavor(options)
10
+
11
+ Dir.chdir(@build_dir)
12
+ @build_cmd = initialize_apk_build_cmd
13
+
14
+ logger_info_and_run_build_command
15
+
16
+ output_apk
17
+ publish_build_app(options) if options.publish?
18
+
19
+ logger_info_blank_line
20
+ end
21
+
22
+ private
23
+
24
+ def set_flavor(options)
25
+ unless options.flavor.blank?
26
+ @flavor = options.flavor
27
+ unless @flavor =~ /^assemble(.+)/
28
+ @flavor = "assemble#{@flavor}Release"
29
+ end
30
+ end
31
+ end
32
+
33
+ def initialize_apk_build_cmd
34
+ check_build_gradle_exist
35
+
36
+ cmd = "./gradlew build"
37
+ cmd = "./gradlew #{@flavor}" unless @flavor.blank?
38
+ cmd
39
+ end
40
+
41
+ def gradle_build_path
42
+ "#{@build_dir}/build/outputs/apk"
43
+ end
44
+
45
+ def prefix_gradle_build_path
46
+ "#{@build_dir}/app/build/outputs/apk"
47
+ end
48
+
49
+ def output_apk
50
+ @builded_apk ||= Dir["#{gradle_build_path}/*.apk"].find { |i| i =~ /release/ }
51
+ @builded_apk ||= Dir["#{prefix_gradle_build_path}/*.apk"].find { |i| i =~ /release/ }
52
+ @builded_apk ||= Dir["#{@build_dir}/*.apk"].find { |i| i =~ /release/ }
53
+
54
+ check_no_output_apk
55
+
56
+ apk_info = FIR.apk_info(@builded_apk)
57
+ @apk_name = @name.blank? ? "#{apk_info[:name]}-#{apk_info[:version]}-Build-#{apk_info[:build]}" : @name
58
+
59
+ @builded_app_path = "#{@output_path}/#{@apk_name}.apk"
60
+ FileUtils.cp(@builded_apk, @builded_app_path)
61
+ end
62
+
63
+ def check_no_output_apk
64
+ unless @builded_apk
65
+ logger.error 'Builded has no output apk'
66
+ exit 1
67
+ end
68
+ end
69
+
70
+ def check_build_gradle_exist
71
+ return if File.exist?("#{@build_dir}/build.gradle")
72
+
73
+ logger.error "The build.gradle isn't exit, please use gradle and edit"
74
+ exit 1
75
+ end
76
+ end
77
+ end