fir-cli 1.7.4.1 → 2.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +0 -2
- data/README.md +8 -1
- data/fir-cli.gemspec +2 -1
- data/lib/fir/cli.rb +5 -3
- data/lib/fir/util/ali_uploader.rb +78 -0
- data/lib/fir/util/app_uploader.rb +111 -0
- data/lib/fir/util/info.rb +2 -0
- data/lib/fir/util/publish.rb +98 -173
- data/lib/fir/util/publisher.rb +34 -0
- data/lib/fir/util/qiniu_uploader.rb +73 -0
- data/lib/fir/version.rb +1 -1
- data/luckin_coffee.png +0 -0
- metadata +16 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 673a534b58afadd5a2b7491884a074dd2db722b636929ac3a43c5de1778e981d
|
4
|
+
data.tar.gz: fcf5a3e79f1bfaf937d6ae13bfed6f40c3f405e59344c797c1fe7a43f8489ddd
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3d62c7e16583cf776c29bbbaec8dfae9104b01534cbf52882545bebf688fda89a51dd928cbd31ae7ccab6ac833fffd1650c13f9c2639f526396c1bdd4ec60a99
|
7
|
+
data.tar.gz: 31d38f670026014742b1a4c1cf87b5f1e33d13bb294266d327dc517a655a395a84629f226285432899c0755882e3304a2ab199b21994f227b348fa54f7d20b53
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -14,6 +14,7 @@ fir.im-cli 可以通过指令查看, 上传, iOS/Android 应用.
|
|
14
14
|
|
15
15
|
|
16
16
|
# 最近更新
|
17
|
+
- (2.0.0) publish 使用更快的存储商, 加速上传速度, 若感觉没以前可使用 switch_to_qiniu 恢复
|
17
18
|
- 支持了在fastlane 直接调用, 具体请参见 [https://github.com/FIRHQ/fastlane-plugin-fir_cli](https://github.com/FIRHQ/fastlane-plugin-fir_cli)
|
18
19
|
- publish 支持 新参数 force_pin_history, 可以 将上传的版本, 固定在下载页面上(当大于最大固定版本数后, 会挤掉最老的固定版本) [2019年11月18日]
|
19
20
|
- publish 支持 新参数 specify_icon_file_path, 可以直接指定 app 的 icon 图标文件 [2019年11月18日]
|
@@ -78,7 +79,7 @@ docker run firhq/fir-cli:latest -e API_TOKEN=XXXX -v ./1.apk:1.apk publish 1.apk
|
|
78
79
|
|
79
80
|
## 提交反馈
|
80
81
|
|
81
|
-
- 联系微信 `atpking
|
82
|
+
- 联系微信 `atpking`, 请注明 "fir-cli 交流"
|
82
83
|
|
83
84
|
- 使用 Github 的 [Issue](https://github.com/FIRHQ/fir-cli/issues)
|
84
85
|
|
@@ -86,3 +87,9 @@ docker run firhq/fir-cli:latest -e API_TOKEN=XXXX -v ./1.apk:1.apk publish 1.apk
|
|
86
87
|
|
87
88
|
- 感谢 sparkrico 提供修正的 https://github.com/sparkrico/ruby_apk 解决了 android 解析的问题
|
88
89
|
|
90
|
+
|
91
|
+
## 鼓励维护
|
92
|
+
|
93
|
+
感谢支持
|
94
|
+
|
95
|
+
![luckin](luckin_coffee.png)
|
data/fir-cli.gemspec
CHANGED
@@ -27,6 +27,7 @@ Gem::Specification.new do |spec|
|
|
27
27
|
/_/ /___/_/ |_| \____/_____/___/
|
28
28
|
|
29
29
|
## 更新记录
|
30
|
+
- (2.0.0) publish 使用更快的存储商, 加速上传速度, 若感觉没以前可使用 switch_to_qiniu 恢复
|
30
31
|
- (1.7.4) 配合 fastlane-plugin-fir_cli 做了一些小优化
|
31
32
|
- (1.7.3) 新增了 上传指定图标, 不上传图标 以及 将版本固定显示在下载页上
|
32
33
|
- (1.7.2) 修正了无论是否加参数都固定出现二维码图片的bug
|
@@ -44,7 +45,7 @@ Gem::Specification.new do |spec|
|
|
44
45
|
# spec.add_development_dependency 'byebug'
|
45
46
|
spec.add_development_dependency 'minitest', '~> 5.7'
|
46
47
|
spec.add_development_dependency 'pry', '~> 0.10'
|
47
|
-
|
48
|
+
|
48
49
|
spec.add_dependency 'thor', '~> 0.19'
|
49
50
|
spec.add_dependency 'rest-client', '~> 2.0'
|
50
51
|
spec.add_dependency 'ruby_android_apk', '~> 0.7.7.1'
|
data/lib/fir/cli.rb
CHANGED
@@ -107,12 +107,14 @@ module FIR
|
|
107
107
|
method_option :short, type: :string, aliases: '-s', desc: 'Set custom short link'
|
108
108
|
method_option :changelog, type: :string, aliases: '-c', desc: 'Set changelog'
|
109
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'
|
110
|
+
method_option :need_release_id, type: :boolean, aliases: '-R', default: false, desc: 'Add release id with fir url (WARNING: FIR ONLY SAVED 30 releases recently per app'
|
111
111
|
|
112
|
-
method_option :force_pin_history, type: :boolean, aliases: '-H', default: false,
|
113
|
-
method_option :skip_update_icon, type: :boolean, aliases: '-S', default: false,
|
112
|
+
method_option :force_pin_history, type: :boolean, aliases: '-H', default: false, desc: 'pin this release to the download page by force'
|
113
|
+
method_option :skip_update_icon, type: :boolean, aliases: '-S', default: false, desc: 'skip update app icon'
|
114
114
|
method_option :specify_icon_file, type: :string, desc: 'specify icon file'
|
115
115
|
|
116
|
+
method_option :switch_to_qiniu, type: :boolean, default: false, aliases: '-N', desc: 'if app upload slowly, u can switch this option'
|
117
|
+
|
116
118
|
method_option :mappingfile, type: :string, aliases: '-m', desc: 'App mapping file'
|
117
119
|
method_option :dingtalk_access_token, type: :string, aliases: '-D', desc: 'Send msg to dingtalk, only need access_token, not whole url'
|
118
120
|
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './app_uploader'
|
4
|
+
# require 'byebug'
|
5
|
+
|
6
|
+
module FIR
|
7
|
+
class AliUploader < AppUploader
|
8
|
+
def upload_icon
|
9
|
+
if skip_update_icon?
|
10
|
+
logger.info 'skip update icon...'
|
11
|
+
return
|
12
|
+
end
|
13
|
+
try_to_action('upload icon') do
|
14
|
+
# 拿到 icon 的授权
|
15
|
+
icon_url = uploading_info[:cert][:icon][:upload_url]
|
16
|
+
icon_info = uploading_icon_info
|
17
|
+
|
18
|
+
logger.debug "icon_url = #{icon_url}, icon_info = #{icon_info}"
|
19
|
+
|
20
|
+
put_file(icon_url, uploading_icon_info, uploading_info[:cert][:icon][:custom_headers])
|
21
|
+
|
22
|
+
callback_to_api(callback_url, callback_icon_information)
|
23
|
+
end
|
24
|
+
rescue StandardError => e
|
25
|
+
# ignore icon error
|
26
|
+
logger.info "ignore icon upload error #{e.message}"
|
27
|
+
end
|
28
|
+
|
29
|
+
def upload_binary
|
30
|
+
try_to_action 'upload binary ...' do
|
31
|
+
binary_url = uploading_info[:cert][:binary][:upload_url]
|
32
|
+
binary_info = uploading_binary_info
|
33
|
+
|
34
|
+
logger.debug "binary_url = #{binary_url}, binary_info = #{binary_info}"
|
35
|
+
headers = uploading_info[:cert][:binary][:custom_headers]
|
36
|
+
headers_copy = {
|
37
|
+
'CONTENT-DISPOSITION' => headers[:"CONTENT-DISPOSITION"],
|
38
|
+
'Content-Type' => headers[:"content-type"],
|
39
|
+
'date' => headers[:date],
|
40
|
+
'x-oss-date' => headers[:"x-oss-date"],
|
41
|
+
'authorization' => headers[:authorization]
|
42
|
+
}
|
43
|
+
|
44
|
+
logger.debug headers_copy
|
45
|
+
put_file(binary_url, binary_info, headers_copy)
|
46
|
+
|
47
|
+
callback_to_api(callback_url, callback_binary_information)
|
48
|
+
end
|
49
|
+
rescue StandardError => e
|
50
|
+
logger.error "binary upload to ali fail, #{e.message}"
|
51
|
+
exit 1
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def put_file(url, file, headers)
|
57
|
+
RestClient::Request.execute(
|
58
|
+
method: 'PUT',
|
59
|
+
url: url,
|
60
|
+
payload: file,
|
61
|
+
headers: headers,
|
62
|
+
timeout: 300
|
63
|
+
)
|
64
|
+
end
|
65
|
+
|
66
|
+
def callback_url
|
67
|
+
"#{fir_api[:base_url]}/auth/ali/callback"
|
68
|
+
end
|
69
|
+
|
70
|
+
def uploading_icon_info
|
71
|
+
File.new(icon_file_path, 'rb')
|
72
|
+
end
|
73
|
+
|
74
|
+
def uploading_binary_info
|
75
|
+
File.new(file_path, 'rb')
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module FIR
|
2
|
+
class AppUploader
|
3
|
+
include ApiTools::DefaultRestModule
|
4
|
+
include Config
|
5
|
+
|
6
|
+
attr_accessor :app_info, :user_info, :uploading_info, :options
|
7
|
+
def initialize(app_info, user_info, uploading_info, options)
|
8
|
+
@app_info = app_info
|
9
|
+
@user_info = user_info
|
10
|
+
@uploading_info = uploading_info
|
11
|
+
@options = options
|
12
|
+
end
|
13
|
+
|
14
|
+
def upload
|
15
|
+
upload_icon
|
16
|
+
binary_callback_info = upload_binary
|
17
|
+
# 将 binary 的callback信息返回
|
18
|
+
binary_callback_info
|
19
|
+
end
|
20
|
+
|
21
|
+
protected
|
22
|
+
|
23
|
+
def callback_to_api(callback_url, callback_binary_information)
|
24
|
+
return if callback_binary_information.blank?
|
25
|
+
|
26
|
+
post callback_url, callback_binary_information
|
27
|
+
end
|
28
|
+
|
29
|
+
def icon_file_path
|
30
|
+
if options[:specify_icon_file].blank?
|
31
|
+
app_info[:icons].max_by { |f| File.size(f) }
|
32
|
+
else
|
33
|
+
File.absolute_path(options[:specify_icon_file])
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
# 是否跳过 icon 上传
|
38
|
+
def skip_update_icon?
|
39
|
+
options[:skip_icon_upload].to_s == 'true'
|
40
|
+
end
|
41
|
+
|
42
|
+
def read_changelog
|
43
|
+
changelog = options[:changelog].to_s.to_utf8
|
44
|
+
return if changelog.blank?
|
45
|
+
|
46
|
+
File.exist?(changelog) ? File.read(changelog) : changelog
|
47
|
+
end
|
48
|
+
|
49
|
+
def icon_cert
|
50
|
+
uploading_info[:cert][:icon]
|
51
|
+
end
|
52
|
+
|
53
|
+
def binary_cert
|
54
|
+
uploading_info[:cert][:binary]
|
55
|
+
end
|
56
|
+
|
57
|
+
def file_path
|
58
|
+
app_info[:file_path]
|
59
|
+
end
|
60
|
+
|
61
|
+
def try_to_action(action, &block)
|
62
|
+
logger.debug "begin to #{action}"
|
63
|
+
answer = block.call
|
64
|
+
logger.debug "#{action} finished"
|
65
|
+
answer
|
66
|
+
rescue StandardError => e
|
67
|
+
logger.error "#{action} error ! #{e.message}"
|
68
|
+
raise e
|
69
|
+
end
|
70
|
+
|
71
|
+
def app_id
|
72
|
+
uploading_info[:id]
|
73
|
+
end
|
74
|
+
|
75
|
+
def callback_icon_information
|
76
|
+
return {} if icon_file_path.nil?
|
77
|
+
{
|
78
|
+
key: icon_cert[:key],
|
79
|
+
token: icon_cert[:token],
|
80
|
+
origin: 'fir-cli',
|
81
|
+
parent_id: app_id,
|
82
|
+
fsize: File.size(icon_file_path),
|
83
|
+
fname: 'blob'
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def callback_binary_information
|
88
|
+
{
|
89
|
+
build: app_info[:build],
|
90
|
+
fname: File.basename(file_path),
|
91
|
+
key: binary_cert[:key],
|
92
|
+
name: app_info[:display_name] || app_info[:name],
|
93
|
+
origin: 'fir-cli',
|
94
|
+
parent_id: app_id,
|
95
|
+
release_tag: 'develop',
|
96
|
+
fsize: File.size(file_path),
|
97
|
+
release_type: app_info[:release_type],
|
98
|
+
distribution_name: app_info[:distribution_name],
|
99
|
+
token: binary_cert[:token],
|
100
|
+
version: app_info[:version],
|
101
|
+
changelog: read_changelog,
|
102
|
+
user_id: user_info[:id]
|
103
|
+
}.reject { |x| x.nil? || x == '' }
|
104
|
+
end
|
105
|
+
|
106
|
+
def logger
|
107
|
+
FIR.logger
|
108
|
+
end
|
109
|
+
|
110
|
+
end
|
111
|
+
end
|
data/lib/fir/util/info.rb
CHANGED
@@ -26,12 +26,14 @@ module FIR
|
|
26
26
|
app = ipa.app
|
27
27
|
info = app.full_info(options)
|
28
28
|
ipa.cleanup
|
29
|
+
info[:file_path] = ipa_path
|
29
30
|
info
|
30
31
|
end
|
31
32
|
|
32
33
|
def apk_info(apk_path, options = {})
|
33
34
|
apk = FIR::Parser::Apk.new(apk_path)
|
34
35
|
info = apk.full_info(options)
|
36
|
+
info[:file_path] = apk_path
|
35
37
|
info
|
36
38
|
end
|
37
39
|
end
|
data/lib/fir/util/publish.rb
CHANGED
@@ -1,146 +1,75 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
# require 'byebug'
|
4
|
+
require_relative './qiniu_uploader'
|
5
|
+
|
6
|
+
require_relative './ali_uploader'
|
7
|
+
|
3
8
|
module FIR
|
4
9
|
module Publish
|
5
10
|
def publish(*args, options)
|
6
11
|
initialize_publish_options(args, options)
|
7
|
-
@options = options
|
8
12
|
check_supported_file_and_token
|
9
|
-
|
10
13
|
logger_info_publishing_message
|
11
14
|
|
12
|
-
|
13
|
-
|
14
|
-
@uploading_info = fetch_uploading_info
|
15
|
-
@app_id = @uploading_info[:id]
|
15
|
+
logger.info 'begin to upload ...'
|
16
|
+
received_app_info = upload_app
|
16
17
|
|
17
|
-
|
18
|
-
|
19
|
-
|
18
|
+
short = received_app_info[:short]
|
19
|
+
release_id = received_app_info[:release_id]
|
20
|
+
|
21
|
+
logger.info 'end upload'
|
20
22
|
|
21
23
|
logger_info_dividing_line
|
22
|
-
logger_info_app_short_and_qrcode
|
23
24
|
|
24
|
-
|
25
|
+
download_url = build_download_url(short, release_id)
|
26
|
+
logger.info "Published succeed: #{download_url}"
|
27
|
+
|
28
|
+
qrcode_path = build_qrcode download_url
|
29
|
+
dingtalk_notifier(download_url, qrcode_path)
|
25
30
|
upload_mapping_file_with_publish
|
31
|
+
|
26
32
|
logger_info_blank_line
|
27
|
-
|
33
|
+
|
28
34
|
{
|
29
35
|
app_id: @app_id,
|
30
|
-
release_id:
|
31
|
-
short:
|
36
|
+
release_id: release_id,
|
37
|
+
short: short
|
32
38
|
}
|
33
39
|
end
|
34
40
|
|
35
|
-
|
36
|
-
user_info = fetch_user_info(@token)
|
41
|
+
protected
|
37
42
|
|
38
|
-
|
39
|
-
|
43
|
+
def logger_info_publishing_message
|
44
|
+
email = @user_info.fetch(:email, '')
|
45
|
+
name = @user_info.fetch(:name, '')
|
40
46
|
|
41
47
|
logger.info "Publishing app via #{name}<#{email}>......."
|
42
48
|
logger_info_dividing_line
|
43
49
|
end
|
44
50
|
|
45
51
|
def upload_app
|
52
|
+
|
53
|
+
app_uploaded_callback_data = if @options[:switch_to_qiniu]
|
54
|
+
QiniuUploader.new(@app_info, @user_info, @uploading_info, @options).upload
|
55
|
+
else
|
56
|
+
AliUploader.new(@app_info, @user_info, @uploading_info, @options).upload
|
57
|
+
end
|
46
58
|
|
47
|
-
|
48
|
-
@binary_cert = @uploading_info[:cert][:binary]
|
49
|
-
logger.debug "in upload app begin to upload icon"
|
50
|
-
upload_app_icon unless @skip_update_icon
|
51
|
-
logger.debug "in upload icon finished"
|
52
|
-
|
53
|
-
logger.debug "in upload app begin to upload binary"
|
54
|
-
@app_uploaded_callback_data = upload_app_binary
|
55
|
-
logger.debug "in upload binary"
|
56
|
-
@release_id = @app_uploaded_callback_data[:release_id]
|
57
|
-
|
58
|
-
force_pin_release if @force_pin_history
|
59
|
+
release_id = app_uploaded_callback_data[:release_id]
|
59
60
|
|
60
61
|
logger.info "App id is #{@app_id}"
|
61
|
-
logger.info "Release id is #{
|
62
|
+
logger.info "Release id is #{release_id}"
|
63
|
+
|
64
|
+
# 处理上传完毕后, 需要的后续操作
|
65
|
+
force_pin_release(release_id) if @force_pin_history
|
62
66
|
upload_device_info
|
63
67
|
update_app_info
|
64
|
-
fetch_app_info
|
65
|
-
end
|
66
68
|
|
67
|
-
|
68
|
-
|
69
|
-
upload_file(word)
|
70
|
-
storage = ENV['SOTRAGE_NAME'] || 'qiniu'
|
71
|
-
information = send("#{word}_information")
|
72
|
-
post("#{fir_api[:base_url]}/auth/#{storage}/callback", information) unless information.blank?
|
73
|
-
end
|
74
|
-
end
|
69
|
+
app_info_dict = fetch_app_info
|
70
|
+
app_info_dict[:release_id] = release_id
|
75
71
|
|
76
|
-
|
77
|
-
logger.info "Uploading app #{postfix}......"
|
78
|
-
url = @uploading_info[:cert][postfix.to_sym][:upload_url]
|
79
|
-
info = send("uploading_#{postfix}_info")
|
80
|
-
logger.debug "url = #{url}, info = #{info}"
|
81
|
-
uploaded_info = post(url, info.merge(manual_callback: true),
|
82
|
-
params_to_json: false,
|
83
|
-
header: nil)
|
84
|
-
rescue StandardError => e
|
85
|
-
logger.error "Uploading app #{postfix} failed"
|
86
|
-
exit 1 if postfix != 'icon'
|
87
|
-
end
|
88
|
-
|
89
|
-
def uploading_icon_info
|
90
|
-
large_icon_path = @app_info[:icons].max_by { |f| File.size(f) }
|
91
|
-
@uncrushed_icon_path = @specify_icon_file_path || convert_icon(large_icon_path)
|
92
|
-
{
|
93
|
-
key: @icon_cert[:key],
|
94
|
-
token: @icon_cert[:token],
|
95
|
-
file: File.new(@uncrushed_icon_path, 'rb'),
|
96
|
-
'x:is_converted' => '1'
|
97
|
-
}
|
98
|
-
end
|
99
|
-
|
100
|
-
def icon_information
|
101
|
-
return {} if @uncrushed_icon_path.nil?
|
102
|
-
{
|
103
|
-
key: @icon_cert[:key],
|
104
|
-
token: @icon_cert[:token],
|
105
|
-
origin: 'fir-cli',
|
106
|
-
parent_id: @app_id,
|
107
|
-
fsize: File.size(@uncrushed_icon_path),
|
108
|
-
fname: 'blob'
|
109
|
-
}
|
110
|
-
end
|
111
|
-
|
112
|
-
def binary_information
|
113
|
-
{
|
114
|
-
build: @app_info[:build],
|
115
|
-
fname: File.basename(@file_path),
|
116
|
-
key: @binary_cert[:key],
|
117
|
-
name: @app_info[:display_name] || @app_info[:name],
|
118
|
-
origin: 'fir-cli',
|
119
|
-
parent_id: @app_id,
|
120
|
-
release_tag: 'develop',
|
121
|
-
fsize: File.size(@file_path),
|
122
|
-
release_type: @app_info[:release_type],
|
123
|
-
distribution_name: @app_info[:distribution_name],
|
124
|
-
token: @binary_cert[:token],
|
125
|
-
version: @app_info[:version],
|
126
|
-
changelog: @changelog,
|
127
|
-
user_id: @user_info[:id]
|
128
|
-
}.reject { |x| x.nil? || x == '' }
|
129
|
-
end
|
130
|
-
|
131
|
-
def uploading_binary_info
|
132
|
-
{
|
133
|
-
key: @binary_cert[:key],
|
134
|
-
token: @binary_cert[:token],
|
135
|
-
file: File.new(@file_path, 'rb'),
|
136
|
-
# Custom variables
|
137
|
-
'x:name' => @app_info[:display_name] || @app_info[:name],
|
138
|
-
'x:build' => @app_info[:build],
|
139
|
-
'x:version' => @app_info[:version],
|
140
|
-
'x:changelog' => @changelog,
|
141
|
-
'x:release_type' => @app_info[:release_type],
|
142
|
-
'x:distribution_name' => @app_info[:distribution_name]
|
143
|
-
}
|
72
|
+
app_info_dict
|
144
73
|
end
|
145
74
|
|
146
75
|
def upload_device_info
|
@@ -151,7 +80,7 @@ module FIR
|
|
151
80
|
post fir_api[:udids_url], key: @binary_cert[:key],
|
152
81
|
udids: @app_info[:devices].join(','),
|
153
82
|
api_token: @token
|
154
|
-
|
83
|
+
end
|
155
84
|
|
156
85
|
def update_app_info
|
157
86
|
update_info = { short: @short, passwd: @passwd, is_opened: @is_opened }.compact
|
@@ -163,27 +92,33 @@ module FIR
|
|
163
92
|
patch fir_api[:app_url] + "/#{@app_id}", update_info.merge(api_token: @token)
|
164
93
|
end
|
165
94
|
|
95
|
+
# 获得 上传文件的授权信息
|
166
96
|
def fetch_uploading_info
|
167
97
|
logger.info "Fetching #{@app_info[:identifier]}@fir.im uploading info......"
|
168
98
|
logger.info "Uploading app: #{@app_info[:name]}-#{@app_info[:version]}(Build #{@app_info[:build]})"
|
169
99
|
|
170
|
-
post fir_api[:app_url],
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
100
|
+
post fir_api[:app_url],
|
101
|
+
{ type: @app_info[:type],
|
102
|
+
bundle_id: @app_info[:identifier],
|
103
|
+
fname: @file_path.split('/').last,
|
104
|
+
force_upload: options[:switch_to_qiniu] ? 'qiniu' : 'ali',
|
105
|
+
skip_icon_upload: @options[:skip_update_icon],
|
106
|
+
manual_callback: true,
|
107
|
+
protocol: 'https',
|
108
|
+
api_token: @token },
|
109
|
+
header: {
|
110
|
+
user_agent: 'new-cli'
|
111
|
+
}
|
179
112
|
end
|
180
113
|
|
181
114
|
def fetch_app_info
|
182
115
|
logger.info 'Fetch app info from fir.im'
|
183
116
|
|
184
|
-
|
185
|
-
write_app_info(id:
|
186
|
-
|
117
|
+
fir_app_info = get(fir_api[:app_url] + "/#{@app_id}", api_token: @token)
|
118
|
+
write_app_info(id: fir_app_info[:id],
|
119
|
+
short: fir_app_info[:short],
|
120
|
+
name: fir_app_info[:name])
|
121
|
+
fir_app_info
|
187
122
|
end
|
188
123
|
|
189
124
|
def upload_mapping_file_with_publish
|
@@ -197,62 +132,67 @@ module FIR
|
|
197
132
|
token: @token
|
198
133
|
end
|
199
134
|
|
200
|
-
def
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
logger.info "
|
205
|
-
|
206
|
-
@qrcode_path = "#{File.dirname(@file_path)}/fir-#{@app_info[:name]}.png"
|
207
|
-
FIR.generate_rqrcode(@download_url, @qrcode_path)
|
208
|
-
|
209
|
-
logger.info "Local qrcode file: #{@qrcode_path}" if @export_qrcode
|
135
|
+
def build_qrcode(download_url)
|
136
|
+
qrcode_path = "#{File.dirname(@file_path)}/fir-#{@app_info[:name]}.png"
|
137
|
+
FIR.generate_rqrcode(download_url, qrcode_path)
|
138
|
+
# 为何在这里必须生成 QrCode ? 因为要在 dingtalk 调用
|
139
|
+
logger.info "Local qrcode file: #{qrcode_path}" if @export_qrcode
|
140
|
+
qrcode_path
|
210
141
|
end
|
211
142
|
|
212
|
-
|
143
|
+
def build_download_url(short, release_id)
|
144
|
+
url = "#{fir_api[:domain]}/#{short}"
|
145
|
+
url += "?release_id=#{release_id}" if options[:need_release_id]
|
146
|
+
url
|
147
|
+
end
|
213
148
|
|
214
149
|
def options
|
215
150
|
@options
|
216
151
|
end
|
217
152
|
|
218
|
-
def force_pin_release
|
219
|
-
post "#{fir_api[:base_url]}/apps/#{@app_id}/releases/#{
|
153
|
+
def force_pin_release(release_id)
|
154
|
+
post "#{fir_api[:base_url]}/apps/#{@app_id}/releases/#{release_id}/force_set_history",
|
220
155
|
api_token: @token
|
221
156
|
end
|
222
157
|
|
223
|
-
def
|
224
|
-
|
225
|
-
end
|
158
|
+
def dingtalk_notifier(download_url, qrcode_path)
|
159
|
+
return if options[:dingtalk_access_token].blank?
|
226
160
|
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
"
|
232
|
-
"
|
233
|
-
"title": "#{title} uploaded",
|
234
|
-
"text": "#{title} uploaded at #{Time.now}\nurl: #{@download_url}\n ![app二维码](data:image/png;base64,#{Base64.strict_encode64(File.read(open(@qrcode_path)))})"
|
235
|
-
}
|
161
|
+
title = "#{@app_info[:name]}-#{@app_info[:version]}(Build #{@app_info[:build]})"
|
162
|
+
payload = {
|
163
|
+
"msgtype": 'markdown',
|
164
|
+
"markdown": {
|
165
|
+
"title": "#{title} uploaded",
|
166
|
+
"text": "#{title} uploaded at #{Time.now}\nurl: #{download_url}\n ![app二维码](data:image/png;base64,#{Base64.strict_encode64(File.read(open(qrcode_path)))})"
|
236
167
|
}
|
237
|
-
|
238
|
-
|
239
|
-
|
168
|
+
}
|
169
|
+
url = "https://oapi.dingtalk.com/robot/send?access_token=#{options[:dingtalk_access_token]}"
|
170
|
+
|
171
|
+
# 用完了二维码, 就删了
|
172
|
+
File.delete(qrcode_path) unless @export_qrcode
|
173
|
+
|
174
|
+
DefaultRest.post(url, payload)
|
240
175
|
rescue StandardError => e
|
241
176
|
logger.warn "Dingtalk send error #{e.message}"
|
242
177
|
end
|
243
178
|
|
244
179
|
def initialize_publish_options(args, options)
|
245
|
-
@
|
246
|
-
@
|
247
|
-
@
|
248
|
-
@
|
249
|
-
@
|
250
|
-
@
|
251
|
-
@
|
180
|
+
@options = options
|
181
|
+
@file_path = File.absolute_path(args.first.to_s)
|
182
|
+
@file_type = File.extname(@file_path).delete('.')
|
183
|
+
@token = options[:token] || current_token
|
184
|
+
@changelog = read_changelog(options[:changelog]).to_s.to_utf8
|
185
|
+
@short = options[:short].to_s
|
186
|
+
@passwd = options[:password].to_s
|
187
|
+
@is_opened = @passwd.blank? ? options[:open] : false
|
252
188
|
@export_qrcode = !!options[:qrcode]
|
189
|
+
@app_info = send("#{@file_type}_info", @file_path, full_info: true)
|
190
|
+
@user_info = fetch_user_info(@token)
|
191
|
+
@uploading_info = fetch_uploading_info # 获得上传信息
|
192
|
+
@app_id = @uploading_info[:id]
|
253
193
|
|
254
|
-
@force_pin_history = options[:force_pin_history]
|
255
194
|
@skip_update_icon = options[:skip_update_icon]
|
195
|
+
@force_pin_history = options[:force_pin_history]
|
256
196
|
@specify_icon_file_path = File.absolute_path(options[:specify_icon_file]) unless options[:specify_icon_file].blank?
|
257
197
|
end
|
258
198
|
|
@@ -268,20 +208,5 @@ module FIR
|
|
268
208
|
check_token_cannot_be_blank(@token)
|
269
209
|
fetch_user_info(@token)
|
270
210
|
end
|
271
|
-
|
272
|
-
def convert_icon(origin_path)
|
273
|
-
# 兼容性不太好, 蔽掉转化图标
|
274
|
-
return origin_path
|
275
|
-
|
276
|
-
logger.info "Converting app's icon......"
|
277
|
-
|
278
|
-
if @app_info[:type] == 'ios'
|
279
|
-
output_path = Tempfile.new(['uncrushed_icon', '.png']).path
|
280
|
-
FIR::Parser::Pngcrush.uncrush_icon(origin_path, output_path)
|
281
|
-
origin_path = output_path if File.size(output_path) != 0
|
282
|
-
end
|
283
|
-
|
284
|
-
origin_path
|
285
|
-
end
|
286
211
|
end
|
287
212
|
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module FIR
|
4
|
+
module Util
|
5
|
+
class Publisher
|
6
|
+
include FIR::Util
|
7
|
+
|
8
|
+
attr_accessor :args, :options
|
9
|
+
|
10
|
+
def initialize(args, options)
|
11
|
+
@file_path = File.absolute_path(args.first.to_s)
|
12
|
+
@file_type = File.extname(@file_path).delete('.')
|
13
|
+
@token = options[:token] || current_token
|
14
|
+
@changelog = read_changelog(options[:changelog]).to_s.to_utf8
|
15
|
+
@short = options[:short].to_s
|
16
|
+
@passwd = options[:password].to_s
|
17
|
+
@is_opened = @passwd.blank? ? options[:open] : false
|
18
|
+
@export_qrcode = !!options[:qrcode]
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def file_path
|
24
|
+
@file_path = File.absolute_path(args.first.to_s)
|
25
|
+
end
|
26
|
+
|
27
|
+
def read_changelog(changelog)
|
28
|
+
return if changelog.blank?
|
29
|
+
|
30
|
+
File.exist?(changelog) ? File.read(changelog) : changelog
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,73 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative './app_uploader'
|
4
|
+
# require 'byebug'
|
5
|
+
|
6
|
+
module FIR
|
7
|
+
class QiniuUploader < AppUploader
|
8
|
+
def upload_icon
|
9
|
+
if skip_update_icon?
|
10
|
+
logger.info 'skip update icon...'
|
11
|
+
return
|
12
|
+
end
|
13
|
+
try_to_action('upload icon') do
|
14
|
+
# 拿到 icon 的授权
|
15
|
+
icon_url = uploading_info[:cert][:icon][:upload_url]
|
16
|
+
icon_info = uploading_icon_info
|
17
|
+
|
18
|
+
logger.debug "icon_url = #{icon_url}, icon_info = #{icon_info}"
|
19
|
+
|
20
|
+
_uploaded_info = post(icon_url, icon_info.merge(manual_callback: true),
|
21
|
+
params_to_json: false,
|
22
|
+
header: nil)
|
23
|
+
|
24
|
+
callback_to_api(callback_url, callback_icon_information)
|
25
|
+
end
|
26
|
+
rescue StandardError => e
|
27
|
+
# ignore icon error
|
28
|
+
logger.info "ignore icon upload error #{e.message}"
|
29
|
+
end
|
30
|
+
|
31
|
+
def upload_binary
|
32
|
+
try_to_action 'upload binary ...' do
|
33
|
+
binary_url = uploading_info[:cert][:binary][:upload_url]
|
34
|
+
binary_info = uploading_binary_info
|
35
|
+
|
36
|
+
_uploaded_info = post(binary_url, binary_info.merge(manual_callback: true),
|
37
|
+
params_to_json: false,
|
38
|
+
header: nil)
|
39
|
+
|
40
|
+
callback_to_api(callback_url, callback_binary_information)
|
41
|
+
end
|
42
|
+
rescue StandardError => e
|
43
|
+
logger.error "binary upload to qiniu fail, #{e.message}"
|
44
|
+
exit 1
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
def callback_url
|
50
|
+
"#{fir_api[:base_url]}/auth/qiniu/callback"
|
51
|
+
end
|
52
|
+
|
53
|
+
# 七牛需要的 icon params
|
54
|
+
def uploading_icon_info
|
55
|
+
icon_cert = uploading_info[:cert][:icon]
|
56
|
+
{
|
57
|
+
key: icon_cert[:key],
|
58
|
+
token: icon_cert[:token],
|
59
|
+
file: File.new(icon_file_path, 'rb')
|
60
|
+
}
|
61
|
+
end
|
62
|
+
|
63
|
+
# 七牛需要的 binary params
|
64
|
+
def uploading_binary_info
|
65
|
+
binary_cert = uploading_info[:cert][:binary]
|
66
|
+
{
|
67
|
+
key: binary_cert[:key],
|
68
|
+
token: binary_cert[:token],
|
69
|
+
file: File.new(file_path, 'rb')
|
70
|
+
}
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
data/lib/fir/version.rb
CHANGED
data/luckin_coffee.png
ADDED
Binary file
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fir-cli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0.beta
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- NaixSpirit
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2019-11-
|
12
|
+
date: 2019-11-21 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -198,6 +198,8 @@ files:
|
|
198
198
|
- lib/fir/patches/os_patch.rb
|
199
199
|
- lib/fir/patches/try.rb
|
200
200
|
- lib/fir/util.rb
|
201
|
+
- lib/fir/util/ali_uploader.rb
|
202
|
+
- lib/fir/util/app_uploader.rb
|
201
203
|
- lib/fir/util/build_apk.rb
|
202
204
|
- lib/fir/util/build_common.rb
|
203
205
|
- lib/fir/util/build_ipa.rb
|
@@ -213,9 +215,12 @@ files:
|
|
213
215
|
- lib/fir/util/parser/ipa.rb
|
214
216
|
- lib/fir/util/parser/pngcrush.rb
|
215
217
|
- lib/fir/util/publish.rb
|
218
|
+
- lib/fir/util/publisher.rb
|
219
|
+
- lib/fir/util/qiniu_uploader.rb
|
216
220
|
- lib/fir/version.rb
|
217
221
|
- lib/fir/xcode_wrapper.sh
|
218
222
|
- lib/fir_cli.rb
|
223
|
+
- luckin_coffee.png
|
219
224
|
- test/build_ipa_test.rb
|
220
225
|
- test/cases/test_apk.apk
|
221
226
|
- test/cases/test_apk_txt
|
@@ -234,12 +239,13 @@ metadata: {}
|
|
234
239
|
post_install_message: "\n ______________ ________ ____\n /
|
235
240
|
____/ _/ __ \\ / ____/ / / _/\n / /_ / // /_/ /_____/ / / / /
|
236
241
|
/\n / __/ _/ // _, _/_____/ /___/ /____/ /\n /_/ /___/_/ |_| \\____/_____/___/\n\n
|
237
|
-
\ ## 更新记录\n - (
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
fork, issue 和 pull
|
242
|
+
\ ## 更新记录\n - (2.0.0) publish 使用更快的存储商, 加速上传速度, 若感觉没以前可使用 switch_to_qiniu 恢复\n
|
243
|
+
\ - (1.7.4) 配合 fastlane-plugin-fir_cli 做了一些小优化\n - (1.7.3) 新增了 上传指定图标, 不上传图标 以及
|
244
|
+
将版本固定显示在下载页上\n - (1.7.2) 修正了无论是否加参数都固定出现二维码图片的bug\n - (1.7.1) 增加了 钉钉推送 , 增加了返回指定版本下载地址\n
|
245
|
+
\ - (1.7.0) 过期了ipa_build 功能, 增加了对 android manifest instant run 的兼容\n - (1.6.13)
|
246
|
+
上传图标逻辑修改\n - (1.6.12) 修复了部分机器没有默认安装 byebug 的问题\n - (1.6.11) 变化了 ruby gem 仓库地址\n
|
247
|
+
\ - [fir-cli](https://github.com/firhq/fir-cli) 已经开源\n - 欢迎 fork, issue 和 pull
|
248
|
+
request\n "
|
243
249
|
rdoc_options: []
|
244
250
|
require_paths:
|
245
251
|
- lib
|
@@ -250,9 +256,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
250
256
|
version: '0'
|
251
257
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
252
258
|
requirements:
|
253
|
-
- - "
|
259
|
+
- - ">"
|
254
260
|
- !ruby/object:Gem::Version
|
255
|
-
version:
|
261
|
+
version: 1.3.1
|
256
262
|
requirements: []
|
257
263
|
rubygems_version: 3.0.3
|
258
264
|
signing_key:
|