ykcitool 0.4.9

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 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