ykcitool 0.4.9

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: be92c75c709e36699e0f5eb29e3aa36568c530c9429799df6a691fed6b2b0875
4
+ data.tar.gz: 7a798df020326ca43df8cc7ac31b3a5c2f98bddfdb884f5272c532d8e5322acf
5
+ SHA512:
6
+ metadata.gz: a39154f25a2e572c4e3d69c248b8b63eef16fd44824b1a0f9d50771ca9a28a9d4711833ff406ae80fb90c39d50bb27ff1dd98cbd3ef4120dcb715b3dbe3fbb20
7
+ data.tar.gz: cc4cf873358b63985af95096455ad5c58ae776cf869ecea3c3a15362b1c742eae38bc5fa7574b16213d67d59a20f1ddb5594b5031c3589fe157f6c1c8345d01e
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2022 stephen.chen
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,253 @@
1
+ # Ykfastlane
2
+
3
+ iOS 通用打包工具的终端门户工具
4
+
5
+ - [Ykfastlane](#ykfastlane)
6
+ - [Installation](#installation)
7
+ - [Usage](#usage)
8
+ - [基础配置](#基础配置)
9
+ - [证书管理](#证书管理)
10
+ - [打包](#打包)
11
+ - [异常情况处理](#异常情况处理)
12
+ - [License](#license)
13
+ - [建议](#建议)
14
+
15
+ ## Installation
16
+
17
+ 本指令集适用与ruby 2.7.5 ~ 3.0.3
18
+
19
+ - 安装ruby
20
+
21
+ ruby版本管理有两种方式 rvm 与 rbenv, 建议使用rbenv.
22
+ 安装对应的ruby版本,建议使用2.7.5;并切换ruby版本到满足需求的版本。
23
+
24
+ - 安装ykfastlane
25
+
26
+ ```shell
27
+ gem install ykcitool
28
+ ```
29
+
30
+ - 做基础配置
31
+ - 安装fastlane脚本
32
+
33
+ ## Usage
34
+
35
+ 安装之后,使用 ykfastlane --help 查看使用说明, 功能分为 通用配置,证书管理,打包三部分。
36
+
37
+ ### 基础配置
38
+
39
+ 基础配置帮助指令
40
+ ```shell
41
+ ykcitool init --help
42
+ ```
43
+ - 设置基础配置 -- ykfastlane init config
44
+
45
+ 本指令集只是一个门户指令,核心打包功能是通过调用fastlane脚本来实现的。
46
+
47
+ 配置:
48
+ - 配置fastlane脚本的远程仓库
49
+
50
+ 此套fastlane脚本是配套脚本;考虑到github的访问问题,可将原始仓库代码迁移到gitlab仓库[^1]。[【原始仓库地址】](https://github.com/stephen5652/ykfastlane_scrip.git)
51
+
52
+ - 配置通知机器人
53
+
54
+ 任务失败时候的,通过企业微信机器人通知开发者[^2]。[【企业微信机器人配置】](https://developer.work.weixin.qq.com/document/path/91770)
55
+
56
+ 用例:
57
+ ```shell
58
+ ykcitool init config -f https://github.com/stephen5652/ykfastlane_scrip.git -t 5ef50d9f-6426-4c4c-94f8-xxxxxxxxxxxx
59
+ ```
60
+
61
+ - 显示基础配置 -- ykfastlane init list_config
62
+
63
+ 在终端打印基础配置的内容
64
+
65
+ 用例
66
+ ```shell
67
+ ykcitool init list_config
68
+ ```
69
+
70
+ - 同步fastlane脚本 -- ykfastlane init sync_script
71
+
72
+ 同步远端fastlane脚本,此处可以通过参数下载固定的fastlan仓库,也可以使用环境配置的仓库来下载。
73
+
74
+ 用例:
75
+ ```shell
76
+ ykcitool init sync_script
77
+ ```
78
+
79
+ ### 证书管理
80
+
81
+ iOS证书管理有多种方案:
82
+
83
+ > - 使用app store connect API进行管理;
84
+ > - 使用fastlane match 管理【适用于单账号】
85
+ > - 半手动管理
86
+
87
+ 考虑到此平台是通用打包平台,且适用于多个Apple账号下的app打包,所以使用半自动管理证书的形式。
88
+ 具体实施方案:
89
+
90
+ > - 账号管理员创建/维护签名证书和描述文件,并上传至证书仓库;
91
+ > - 开发者电脑,打包机同步证书仓库,并安装证书和描述文件;
92
+ > - 各个项目配置手动签名配置;
93
+ > - 打包平台依据项目签名配置,进行打包。
94
+
95
+ 操作步骤:
96
+
97
+ - 管理员,开发者,打包机电脑配置证书仓库
98
+
99
+ 指令集通过git仓库来维护证书。
100
+
101
+ 指令
102
+ ```shell
103
+ ykcitool certificate edit_config -r http://xxx.xxx.com/xxx.git
104
+ ```
105
+
106
+ 指令集支持显示证书仓库配置
107
+
108
+ 指令:
109
+ ```shell
110
+ ykcitool certificate list_config
111
+ ```
112
+
113
+ - 管理员更新证书
114
+
115
+ 使用脚本平台,更新证书,并推送至证书仓库
116
+
117
+ 指令:
118
+
119
+ ```shell
120
+ ykcitool certificate update_cer -c /Users/xxx/xxx/xxxx.p12 -p xxxx
121
+ ```
122
+
123
+ - 管理员更新描述文件
124
+
125
+ 使用脚本平台,更新描述文件,并推送至证书仓库。
126
+
127
+ 指令:
128
+
129
+ ```shell
130
+ ykcitool certificate update_profile -p /Users/xxx/xxx/xxx.mobileprovision
131
+ ```
132
+
133
+ - 同步证书和描述文件
134
+
135
+ 开发者,打包机通过平台同步证书仓库。
136
+
137
+ 指令:
138
+
139
+ ```shell
140
+ ykcitool certificate sync-cer
141
+ ```
142
+
143
+ - 显示证书和描述文件
144
+
145
+ 指令集支持显示证书仓库中的证书和描述文件
146
+
147
+ 指令:
148
+
149
+ ```shell
150
+ ykcitool certificate list_cers
151
+ ```
152
+
153
+ - 缺点
154
+
155
+ 此种形式的证书管理,也是存在缺点的。
156
+
157
+ 缺点:
158
+
159
+ - 多个Apple账号的证书在同一个git仓库管理;
160
+ - 每台电脑都安装了所有Apple账号的证书和项目描述文件。
161
+
162
+ ### 打包
163
+
164
+ 指令集通过调用fastlane脚本进行打包,依据发不的平台,分为三种打包:fir平台,蒲公英平台,TF
165
+
166
+ - fir打包
167
+
168
+ - 打包指令帮助:
169
+
170
+ ```shell
171
+ ykcitool archive fire --help
172
+ ```
173
+
174
+ - 使用方式
175
+
176
+ 支持两种打包方式, 在.xcworkspace 路径打包 / 在其他目录打包。
177
+
178
+ > 在 .xcworkspace 同级打包
179
+ > ```shell
180
+ > ykcitool archive fire -s XXXX -f xxxx -e enterprise -n "iOS测试包" -w xxxx
181
+ > ```
182
+
183
+ > 在其他目录打包:
184
+ 由于.xcworkspace未必在git仓库根目录,所以可以用参数 -x 指定 .xcworkspace 的相对路径 </br>
185
+ 如果终端工作路径在 .xcworkspace同级目录,则可以不使用参数 -x </br>
186
+ 如果不用专门通知企业微信业务群,可以不指定 -w 参数,会默认使用env中配置的企微机器人。</br>
187
+ > ```shell
188
+ > ykcitool archive fire -s XXXX -x ~/users/xxx/xxx/xxxx.xcworkspace -f xxxx -e enterprise -n "iOS测试包" -w xxxx
189
+ > ```
190
+
191
+ - 蒲公英打包
192
+
193
+ 使用方式同 fir 打包
194
+
195
+
196
+ - TF打包
197
+
198
+ 由于TF打包一定是app store包,所以此指令没有 -e 参数,无法指定包类型
199
+ - 打包指令帮助:
200
+ ```shell
201
+ ykcitool archive tf --help
202
+ ```
203
+
204
+ - 使用方式
205
+
206
+ 通用支持两种打包方式, 通过 -x 参数来指定 .xcworkspace 的路径
207
+ > 此处需要特别说明 -u -p -w -c 参数 </br>
208
+ -u 开发者的Apple ID </br>
209
+ -p 开发者Apple ID的App专属密钥[^3]。[【传送门】](https://appleid.apple.com/account/manage) </br>
210
+ -w 企微机器人,如果不指定,则默认使用env中配置的机器人。 </br>
211
+ -c 是否需要pod install, 默认不执行。
212
+
213
+ 指令范例:
214
+ ```shell
215
+ ykcitool archive tf -s XXX -u xxxx.@xxx.com -p xxxx-xxxx-xxxx-xxxx -n iOS测试包 -w xxxxx -c 1
216
+ ```
217
+
218
+ ## 异常情况处理
219
+
220
+ - public_suffix 版本冲突
221
+
222
+ - 清空gem
223
+
224
+ ```shell
225
+ gem clean
226
+ ```
227
+
228
+ - 卸载 public_suffix
229
+
230
+ ```shell
231
+ gem uninstall public_suffix
232
+ ```
233
+
234
+ ## License
235
+
236
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
237
+
238
+ [^1]:fastlane脚本原始仓库地址: https://github.com/stephen5652/ykfastlane_scrip.git
239
+
240
+ [^2]:企业微信机器人配置网址: https://developer.work.weixin.qq.com/document/path/91770
241
+
242
+ [^3]: 配置App专属密钥的网址: https://appleid.apple.com/account/manage
243
+
244
+
245
+ ### 建议
246
+
247
+ fire-api-token 做全局配置
248
+
249
+ tf tag参数化,可以控制是否打tag
250
+
251
+ builde 号不交付苹果管理,指令集也不管理,交由工程配置
252
+
253
+ 显示打包结果的存储路径
data/bin/ykcitool ADDED
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+ #
4
+
5
+ puts "call ykcitool"
6
+
7
+ lib = File.expand_path(File.dirname(__FILE__) + '/../lib')
8
+ $LOAD_PATH.unshift(lib) if File.directory?(lib) && !$LOAD_PATH.include?(lib)
9
+
10
+ # You can add fixtures and/or initialization code here to make experimenting
11
+ # with your gem easier. You can also use a different console, if you like.
12
+
13
+ # (If you use this, don't forget to add pry to your Gemfile!)
14
+ # require "pry"
15
+ # Pry.start
16
+ require 'interface'
17
+ puts "call ykcitool:#{YKFastlane::VERSION}"
18
+
19
+ puts "ykcitool start"
20
+ YKFastlane::Interface.start(ARGV)
@@ -0,0 +1,109 @@
1
+ require 'ykfastlane/helper'
2
+
3
+ require 'git'
4
+ require 'json'
5
+
6
+ module YKFastlane
7
+ module GitAnalysis
8
+ include Git
9
+
10
+ def self.commit_tag_diff(path)
11
+ git = Git::open(path)
12
+ last_tag = self.last_tag_on_branch(git)
13
+ tag_name = last_tag.name unless last_tag == nil
14
+
15
+ tag_commit = last_tag.log(1).last unless last_tag == nil
16
+ tag_commit = git.log(0x7fffffff).last if tag_commit == nil
17
+ tag_sha = tag_commit.sha unless tag_commit == nil
18
+
19
+ cur_commit = git.log(1).first
20
+ cur_sha = cur_commit.sha unless cur_commit == nil
21
+
22
+ diff = self.diff_between?(path, tag_sha, cur_sha)
23
+
24
+ result = {
25
+ :tag_name => tag_name,
26
+ }
27
+ result.update(diff)
28
+ result
29
+ end
30
+
31
+
32
+ def commit_tag_diff(path)
33
+ YKFastlane::GitAnalysis.commit_tag_diff(path)
34
+ end
35
+
36
+ private
37
+
38
+ def self.sha_existed?(git, sha)
39
+ result = true
40
+ begin
41
+ start_type = git.lib.object_type(sha)
42
+ rescue Git::GitExecuteError => e
43
+ result = false
44
+ end
45
+ result
46
+ end
47
+
48
+ def self.diff_between?(path, id_start, id_end)
49
+ git = Git::open(path)
50
+
51
+ # id_start = "0d5e5d4d7e8f8a9b" #debug code
52
+ # id_end = "2347682023948" #debug code
53
+ status = true
54
+ msg_arr = []
55
+ if self.sha_existed?(git, id_start) == false
56
+ status = false
57
+ msg_arr << id_start
58
+ end
59
+
60
+ if self.sha_existed?(git, id_end) == false
61
+ status = false
62
+ msg_arr << id_end
63
+ end
64
+
65
+ msg = "success"
66
+ msg = "diff check failed, since commit not existed: " + msg_arr.join(" ") unless status == true
67
+
68
+ diff = nil
69
+ if status
70
+ c_start = git.gcommit(id_start)
71
+ c_end = git.gcommit(id_end)
72
+ diff = git.diff(c_start, c_end) #Git::Diff
73
+ end
74
+
75
+
76
+ remotes = git.remotes
77
+ remote_dict = {}
78
+ remotes.each do |one|
79
+ #Git::Remote
80
+ remote_dict[one.name] = one.url
81
+ end
82
+ result = {
83
+ :status => status,
84
+ :message => msg,
85
+ :remote_info => remote_dict,
86
+ :start_commit => id_start,
87
+ :end_commit => id_end,
88
+ :stats => diff == nil ? {} : diff.stats,
89
+ }
90
+
91
+ puts("diff_detail:#{result.to_json}")
92
+ result
93
+ end
94
+
95
+ def self.last_tag_on_branch(git)
96
+ last_tag_name = nil
97
+
98
+ begin
99
+ last_tag_name = git.describe(nil, { :abbrev => 0 })
100
+ rescue Git::GitExecuteError => e
101
+ puts "find last tag failed:#{e}"
102
+ end
103
+ tag = git.tag(last_tag_name) unless last_tag_name.blank?
104
+
105
+ tag
106
+ end
107
+
108
+ end
109
+ end
@@ -0,0 +1,28 @@
1
+ require 'ykfastlane/helper'
2
+ require 'actions/init'
3
+
4
+ require 'agoo'
5
+ module YKHttpModule
6
+ module YKHttpHelper
7
+
8
+ require 'HttpService/git_tag_analysis_handler'
9
+
10
+ def self.startService(port)
11
+ puts("should start http service at port:#{port}")
12
+ Agoo::Server.init(6464, 'root')
13
+
14
+ tag_diff = YKHttpModule::GitTagDiff.new
15
+ Agoo::Server.handle(:POST, "/tag_diff", tag_diff)
16
+
17
+ commit_diff = YKHttpModule::GitCommitDiff.new
18
+ Agoo::Server.handle(:GET, "/commit_diff", commit_diff)
19
+
20
+ Agoo::Server.start()
21
+
22
+ end
23
+
24
+ def self.stopService()
25
+ puts("should stop http service")
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,20 @@
1
+ module YKHttpModule
2
+ require 'GitTools/git_analysis'
3
+
4
+ class GitTagDiff
5
+ def call(req)
6
+ puts("tag_diff[#{self}]:#{req}")
7
+ [ 200, { }, [ "#{req}" ] ]
8
+ end
9
+ end
10
+
11
+ class GitCommitDiff
12
+ def call(req)
13
+ puts("commit_diff[#{self}]:#{req}")
14
+ YKFastlane::Init.new().list_all_configs
15
+ path = Dir.pwd
16
+ result = YKFastlane::GitAnalysis.commit_tag_diff(path)
17
+ [ 200, { }, [ "#{result}" ] ]
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,89 @@
1
+ require 'rails'
2
+ require 'thor'
3
+
4
+ require "ykfastlane/helper"
5
+
6
+ module YKFastlane
7
+
8
+ class SubCommandBase < Thor
9
+ class_option :verbose, :type => :boolean
10
+ def self.exit_on_failure?
11
+ true
12
+ end
13
+
14
+ def self.banner(command, namespace = nil, subcommand = false)
15
+ "#{basename} #{subcommand_prefix} #{command.usage}"
16
+ end
17
+
18
+ def self.subcommand_prefix
19
+ self.name.gsub(%r{.*::}, '').gsub(%r{^[A-Z]}) { |match| match[0].downcase }.gsub(%r{[A-Z]}) { |match| "-#{match[0].downcase}" }
20
+ end
21
+ end
22
+
23
+ class YKFastlaneExecute
24
+ def self.executeCommand(commandShell_pre, commandShell, workTitle)
25
+ excuteStr = " "
26
+ excuteStr << "#{commandShell_pre}" unless commandShell_pre.blank?
27
+ excuteStr << " && #{commandShell}" unless commandShell.blank?
28
+
29
+ puts "START COMMAND:#{excuteStr}"
30
+ code = 1
31
+ system(excuteStr)
32
+ result = $?
33
+ puts "command result[#{result.class}]:#{result}"
34
+ code = result.exitstatus if result.is_a?(Process::Status)
35
+
36
+ #### 以下代码注释,因为fastlane脚本中做了任务失败时候的通知
37
+ # if code != 0
38
+ # #任务失败, 此处需要发送企业微信的通知到开发群
39
+ # puts "should report error to developer group"
40
+ # noticeCmd = commandShell_pre
41
+ # commandShell = commandShell.gsub!( " ", "\\ " )
42
+ # commandShell = commandShell.gsub!( "\"", "\\\"")
43
+ # noticeCmd << "&&fastlane wx_message_notice wx_notice_token:#{Helper::YKWECHAT_ROBOT_TOKEN} msg_title:\"CI work failed\" notice_message:\"#{commandShell}\""
44
+ # puts "notice_command:#{noticeCmd}"
45
+ # system(noticeCmd)
46
+ # end
47
+
48
+ code
49
+ end
50
+
51
+ def self.exchangOptionMapToStr(optionHash)
52
+ paras = {}
53
+ optionHash.each_pair { |k, v| paras[k] = v }
54
+ puts "paras:#{paras.dup}"
55
+
56
+ puts "YKRUNING_PATH:#{Helper::YKRUNING_PATH}"
57
+ workspace_path = Helper::YKRUNING_PATH
58
+ workspace_path = paras["xcworkspace"] unless paras["xcworkspace"].blank?
59
+ paras[:xcworkspace] = workspace_path
60
+ paras[:script_run_path] = Helper::YKRUNING_PATH
61
+
62
+ puts "options_after:#{paras}"
63
+ option_str = ""
64
+ paras.each_pair do |k, v|
65
+ option_str << " #{k}:\"#{v}\""
66
+ end
67
+ option_str
68
+ end
69
+
70
+ def self.executeFastlaneLane(lane_name, optionHash)
71
+ dict = {}
72
+ dict.update(optionHash)
73
+ if optionHash[:wxwork_access_token].blank?
74
+ wxtoken = YKFastlane::Helper.load_config_value(YKFastlane::Helper::K_wx_access_token)
75
+ dict.update({:wxwork_access_token => wxtoken})
76
+ end
77
+
78
+ option_str = exchangOptionMapToStr(dict)
79
+ command = "fastlane #{lane_name} #{option_str}" unless option_str.blank?
80
+
81
+ command_pre = "export LANG=en_US.UTF-8 && export LANGUAGE=en_US.UTF-8 && export LC_ALL=en_US.UTF-8 && which ruby"
82
+ command_pre << " && cd #{YKFastlane::Helper.fastlane_script()}"
83
+
84
+ executeCommand(command_pre, command, lane_name)
85
+ end
86
+
87
+ end
88
+
89
+ end