fir-cli-x 1.7.2.1

Sign up to get free protection for your applications and to get access to all the features.
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
data/lib/fir-cli.rb ADDED
@@ -0,0 +1,3 @@
1
+ # encoding: utf-8
2
+ # This file exists for backward compatbility with require 'fir-cli'
3
+ require_relative './fir'
data/lib/fir.rb ADDED
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'thor'
4
+ require 'logger'
5
+ require 'yaml'
6
+ require 'rest-client'
7
+ require 'json'
8
+ require 'securerandom'
9
+ require 'fileutils'
10
+ require 'cfpropertylist'
11
+ require 'tempfile'
12
+ require 'rqrcode'
13
+
14
+ # TODO: remove rescue when https://github.com/tajchert/ruby_apk/pull/4 merged
15
+ begin
16
+ require 'ruby_android'
17
+ rescue LoadError
18
+ require 'ruby_apk'
19
+ end
20
+
21
+ require 'fir/patches'
22
+ require 'fir/util'
23
+ require 'fir/version'
24
+ require 'fir/cli'
25
+
26
+ module FIR
27
+ include Util
28
+ end
data/lib/fir/api.yml ADDED
@@ -0,0 +1,7 @@
1
+ fir:
2
+ domain: 'http://fir.im'
3
+ base_url: 'http://api.fir.im'
4
+ user_url: 'http://api.fir.im/user'
5
+ app_url: 'http://api.fir.im/apps'
6
+ udids_url: 'http://api.fir.im/devices/multi_udid'
7
+
data/lib/fir/cli.rb ADDED
@@ -0,0 +1,181 @@
1
+ # frozen_string_literal: true
2
+
3
+ module FIR
4
+ class CLI < Thor
5
+ class_option :token, type: :string, aliases: '-T', desc: "User's API Token at fir.im"
6
+ class_option :logfile, type: :string, aliases: '-L', desc: 'Path to writable logfile'
7
+ class_option :verbose, type: :boolean, aliases: '-V', desc: 'Show verbose', default: true
8
+ class_option :quiet, type: :boolean, aliases: '-q', desc: 'Silence commands'
9
+ class_option :help, type: :boolean, aliases: '-h', desc: 'Show this help message and quit'
10
+
11
+ desc '(EXPIRED, PLEASE use fastlane instead) build_ipa BUILD_DIR [options] [settings]', 'Build iOS app (alias: `bi`).'
12
+ long_desc <<-LONGDESC
13
+ `build_ipa` command will auto build your project/workspace to an ipa package
14
+ and it also can auto publish your built ipa to fir.im if use `-p` option.
15
+ Internally, it use `xcodebuild` to accomplish these things, use `man xcodebuild` to get more information.
16
+
17
+ Example:
18
+
19
+ $ fir bi <project dir> [-C <configuration>] [-t <target name>] [-o <ipa output dir>] [settings] [-c <changelog>] [-p -Q -T <your api token>]
20
+
21
+ $ fir bi <project dir> [-c <changelog> -P <bughd project id> -M -p -Q -T <your api token>]
22
+
23
+ $ fir bi <git ssh url> [-B develop -c <changelog> -f <profile> -P <bughd project id> -M -p -Q -T <your api token>]
24
+
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
+ LONGDESC
27
+ map %w[b bi] => :build_ipa
28
+ method_option :branch, type: :string, aliases: '-B', desc: 'Set branch if project is a git repo, the default is `master`'
29
+ method_option :workspace, type: :boolean, aliases: '-w', desc: 'true/false if build workspace'
30
+ method_option :scheme, type: :string, aliases: '-S', desc: 'Set the scheme NAME if build workspace'
31
+ method_option :configuration, type: :string, aliases: '-C', desc: 'Use the build configuration NAME for building each target'
32
+ method_option :destination, type: :string, aliases: '-d', desc: 'Set the destination specifier'
33
+ method_option :target, type: :string, aliases: '-t', desc: 'Build the target specified by target name'
34
+ method_option :export_method, type: :string, aliases: '-E', desc: 'for exportOptionsPlist method, ad-hoc as default'
35
+ method_option :optionPlistPath, type: :string, aliases: '-O', desc: 'User defined exportOptionsPlist path'
36
+ method_option :profile, type: :string, aliases: '-f', desc: 'Set the export provisioning profile'
37
+ method_option :output, type: :string, aliases: '-o', desc: 'IPA output path, the default is: BUILD_DIR/fir_build_ipa'
38
+ method_option :publish, type: :boolean, aliases: '-p', desc: 'true/false if publish to fir.im'
39
+ method_option :short, type: :string, aliases: '-s', desc: 'Set custom short link if publish to fir.im'
40
+ method_option :name, type: :string, aliases: '-n', desc: 'Set custom ipa name when built'
41
+ method_option :changelog, type: :string, aliases: '-c', desc: 'Set changelog if publish to fir.im'
42
+ method_option :qrcode, type: :boolean, aliases: '-Q', desc: 'Generate qrcode'
43
+ method_option :mapping, type: :boolean, aliases: '-M', desc: 'true/false if upload app mapping file to BugHD.com'
44
+ method_option :proj, type: :string, aliases: '-P', desc: 'Project id in BugHD.com if upload app mapping file'
45
+ method_option :open, type: :boolean, desc: 'true/false if open for everyone'
46
+ method_option :password, type: :string, desc: 'Set password for app'
47
+ def build_ipa(*args)
48
+ prepare :build_ipa
49
+
50
+ FIR.build_ipa(*args, options)
51
+ end
52
+
53
+ desc 'build_apk BUILD_DIR', 'Build Android app (alias: `ba`).'
54
+ long_desc <<-LONGDESC
55
+ `build_apk` command will auto build your project to an apk package
56
+ and it also can auto publish your built apk to fir.im if use `-p` option.
57
+ Internally, it use `gradle` to accomplish these things, use `gradle --help` to get more information.
58
+
59
+ Example:
60
+
61
+ $ fir ba <project dir> [-o <apk output dir> -c <changelog> -p -Q -T <your api token>]
62
+
63
+ $ fir ba <project dir> [-f <flavor> -o <apk output dir> -c <changelog> -p -Q -T <your api token>]
64
+
65
+ $ fir ba <git ssh url> [-B develop -o <apk output dir> -c <changelog> -p -Q -T <your api token>]
66
+ LONGDESC
67
+ map ['ba'] => :build_apk
68
+ method_option :branch, type: :string, aliases: '-B', desc: 'Set branch if project is a git repo, the default is `master`'
69
+ method_option :output, type: :string, aliases: '-o', desc: 'APK output path, the default is: BUILD_DIR/build/outputs/apk'
70
+ method_option :publish, type: :boolean, aliases: '-p', desc: 'true/false if publish to fir.im'
71
+ method_option :flavor, type: :string, aliases: '-f', desc: 'Set flavor if have productFlavors'
72
+ method_option :short, type: :string, aliases: '-s', desc: 'Set custom short link if publish to fir.im'
73
+ method_option :name, type: :string, aliases: '-n', desc: 'Set custom apk name when builded'
74
+ method_option :changelog, type: :string, aliases: '-c', desc: 'Set changelog if publish to fir.im, support string/file'
75
+ method_option :qrcode, type: :boolean, aliases: '-Q', desc: 'Generate qrcode'
76
+ method_option :open, type: :boolean, desc: 'true/false if open for everyone, the default is: true', default: true
77
+ method_option :password, type: :string, desc: 'Set password for app'
78
+ def build_apk(*args)
79
+ prepare :build_apk
80
+
81
+ FIR.build_apk(*args, options)
82
+ end
83
+
84
+ desc 'info APP_FILE_PATH', 'Show iOS/Android app info, support ipa/apk file (aliases: `i`).'
85
+ map 'i' => :info
86
+ method_option :all, type: :boolean, aliases: '-a', desc: 'Show all information in application'
87
+ def info(*args)
88
+ prepare :info
89
+
90
+ FIR.info(*args, options)
91
+ end
92
+
93
+ desc 'publish APP_FILE_PATH', 'Publish iOS/Android app to fir.im, support ipa/apk file (aliases: `p`).'
94
+ long_desc <<-LONGDESC
95
+ `publish` command will publish your app file to fir.im, also the command support to publish app's short & changelog.
96
+
97
+
98
+ Example:
99
+
100
+ $ fir p <app file path> [-c <changelog> -s <custom short link> -Q -T <your api token>]
101
+
102
+ $ fir p <app file path> [-c <changelog> -s <custom short link> --password=123456 --open=false -Q -T <your api token>]
103
+
104
+ $ fir p <app file path> [-c <changelog> -s <custom short link> -m <mapping file path> -P <bughd project id> -Q -T <your api token>]
105
+ LONGDESC
106
+ map 'p' => :publish
107
+ method_option :short, type: :string, aliases: '-s', desc: 'Set custom short link'
108
+ method_option :changelog, type: :string, aliases: '-c', desc: 'Set changelog'
109
+ method_option :qrcode, type: :boolean, aliases: '-Q', desc: 'Generate qrcode'
110
+ method_option :need_release_id, type: :boolean, aliases: '-R', desc: 'Add release id with fir url (WARNING: FIR ONLY SAVED 30 releases recently per app'
111
+
112
+ method_option :mappingfile, type: :string, aliases: '-m', desc: 'App mapping file'
113
+ method_option :dingtalk_access_token, type: :string, aliases: '-D', desc: 'Send msg to dingtalk, only need access_token, not whole url'
114
+
115
+ method_option :open, type: :boolean, desc: 'true/false if open for everyone'
116
+ method_option :password, type: :string, desc: 'Set password for app'
117
+ def publish(*args)
118
+ prepare :publish
119
+
120
+ FIR.publish(*args, options)
121
+ end
122
+
123
+ desc 'login', 'Login fir.im (aliases: `l`).'
124
+ map 'l' => :login
125
+ def login(*args)
126
+ prepare :login
127
+
128
+ token = options[:token] || args.first || ask('Please enter your fir.im API Token:', :white, echo: true)
129
+ FIR.login(token)
130
+ end
131
+
132
+ desc 'me', 'Show current user info if user is logined.'
133
+ def me
134
+ prepare :me
135
+
136
+ FIR.me
137
+ end
138
+
139
+ desc 'upgrade', 'Upgrade fir-cli and quit (aliases: `u`).'
140
+ map 'u' => :upgrade
141
+ def upgrade
142
+ prepare :upgrade
143
+
144
+ say '✈ Upgrade fir-cli (use `gem install fir-cli --no-ri --no-rdoc`)'
145
+ say `gem install fir-cli --no-ri --no-rdoc`
146
+ end
147
+
148
+ desc 'version', 'Show fir-cli version number and quit (aliases: `v`).'
149
+ map ['v', '-v', '--version'] => :version
150
+ def version
151
+ say "✈ fir-cli #{FIR::VERSION}"
152
+ end
153
+
154
+ desc 'help', 'Describe available commands or one specific command (aliases: `h`).'
155
+ map Thor::HELP_MAPPINGS => :help
156
+ def help(command = nil, subcommand = false)
157
+ super
158
+ end
159
+
160
+ no_commands do
161
+ def invoke_command(command, *args)
162
+ logfile = options[:logfile].blank? ? STDOUT : options[:logfile]
163
+ logfile = '/dev/null' if options[:quiet]
164
+
165
+ FIR.logger = Logger.new(logfile)
166
+ FIR.logger.level = options[:verbose] ? Logger::INFO : Logger::ERROR
167
+ super
168
+ end
169
+ end
170
+
171
+ private
172
+
173
+ def prepare(task)
174
+ if options.help?
175
+ help(task.to_s)
176
+ raise SystemExit
177
+ end
178
+ $DEBUG = true if ENV['DEBUG']
179
+ end
180
+ end
181
+ end
@@ -0,0 +1,10 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative './patches/blank'
4
+ require_relative './patches/concern'
5
+ require_relative './patches/hash'
6
+ require_relative './patches/instance_variables'
7
+ require_relative './patches/native_patch'
8
+ require_relative './patches/os_patch'
9
+ require_relative './patches/try'
10
+ require_relative './patches/default_headers'
@@ -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,146 @@
1
+ # encoding: utf-8
2
+
3
+ module ActiveSupport
4
+ # A typical module looks like this:
5
+ #
6
+ # module M
7
+ # def self.included(base)
8
+ # base.extend ClassMethods
9
+ # base.class_eval do
10
+ # scope :disabled, -> { where(disabled: true) }
11
+ # end
12
+ # end
13
+ #
14
+ # module ClassMethods
15
+ # ...
16
+ # end
17
+ # end
18
+ #
19
+ # By using <tt>ActiveSupport::Concern</tt> the above module could instead be
20
+ # written as:
21
+ #
22
+ # require 'active_support/concern'
23
+ #
24
+ # module M
25
+ # extend ActiveSupport::Concern
26
+ #
27
+ # included do
28
+ # scope :disabled, -> { where(disabled: true) }
29
+ # end
30
+ #
31
+ # class_methods do
32
+ # ...
33
+ # end
34
+ # end
35
+ #
36
+ # Moreover, it gracefully handles module dependencies. Given a +Foo+ module
37
+ # and a +Bar+ module which depends on the former, we would typically write the
38
+ # following:
39
+ #
40
+ # module Foo
41
+ # def self.included(base)
42
+ # base.class_eval do
43
+ # def self.method_injected_by_foo
44
+ # ...
45
+ # end
46
+ # end
47
+ # end
48
+ # end
49
+ #
50
+ # module Bar
51
+ # def self.included(base)
52
+ # base.method_injected_by_foo
53
+ # end
54
+ # end
55
+ #
56
+ # class Host
57
+ # include Foo # We need to include this dependency for Bar
58
+ # include Bar # Bar is the module that Host really needs
59
+ # end
60
+ #
61
+ # But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We
62
+ # could try to hide these from +Host+ directly including +Foo+ in +Bar+:
63
+ #
64
+ # module Bar
65
+ # include Foo
66
+ # def self.included(base)
67
+ # base.method_injected_by_foo
68
+ # end
69
+ # end
70
+ #
71
+ # class Host
72
+ # include Bar
73
+ # end
74
+ #
75
+ # Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
76
+ # is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
77
+ # module dependencies are properly resolved:
78
+ #
79
+ # require 'active_support/concern'
80
+ #
81
+ # module Foo
82
+ # extend ActiveSupport::Concern
83
+ # included do
84
+ # def self.method_injected_by_foo
85
+ # ...
86
+ # end
87
+ # end
88
+ # end
89
+ #
90
+ # module Bar
91
+ # extend ActiveSupport::Concern
92
+ # include Foo
93
+ #
94
+ # included do
95
+ # self.method_injected_by_foo
96
+ # end
97
+ # end
98
+ #
99
+ # class Host
100
+ # include Bar # It works, now Bar takes care of its dependencies
101
+ # end
102
+ module Concern
103
+ class MultipleIncludedBlocks < StandardError #:nodoc:
104
+ def initialize
105
+ super "Cannot define multiple 'included' blocks for a Concern"
106
+ end
107
+ end
108
+
109
+ def self.extended(base) #:nodoc:
110
+ base.instance_variable_set(:@_dependencies, [])
111
+ end
112
+
113
+ def append_features(base)
114
+ if base.instance_variable_defined?(:@_dependencies)
115
+ base.instance_variable_get(:@_dependencies) << self
116
+ return false
117
+ else
118
+ return false if base < self
119
+ @_dependencies.each { |dep| base.send(:include, dep) }
120
+ super
121
+ base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
122
+ base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
123
+ end
124
+ end
125
+
126
+ def included(base = nil, &block)
127
+ if base.nil?
128
+ fail MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
129
+
130
+ @_included_block = block
131
+ else
132
+ super
133
+ end
134
+ end
135
+
136
+ def class_methods(&class_methods_module_definition)
137
+ if const_defined?(:ClassMethods, false)
138
+ mod = const_get(:ClassMethods)
139
+ else
140
+ mod = const_set(:ClassMethods, Module.new)
141
+ end
142
+
143
+ mod.module_eval(&class_methods_module_definition)
144
+ end
145
+ end
146
+ end