Gitlab CI 编译 Android APK

不希望把时间,浪费在打包 APK 这个事情上。集成自动打包工具

安装 gitlab-runner

1
2
3
curl -L https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh | sudo bash

apt install gitlab-runner

注册 gitlab-runner

1
gitlab-runner register
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# 实际操作如下
root@vm:/home/x# gitlab-runner register
Runtime platform arch=amd64 os=linux pid=208812 revision=4e1f20da version=13.4.0
Running in system-mode.

Please enter the gitlab-ci coordinator URL (e.g. https://gitlab.com/):
https://192.168.2.3:8080/
Please enter the gitlab-ci token for this runner:
ymfhzJQBxysj1xjfPftU
Please enter the gitlab-ci description for this runner:
[vm]: CI Android Docker
Please enter the gitlab-ci tags for this runner (comma separated):
build-test
Registering runner... succeeded runner=ymfhzJQB
Please enter the executor: ssh, virtualbox, docker+machine, custom, docker, docker-ssh, parallels, shell, docker-ssh+machine, kubernetes:
docker
Please enter the default Docker image (e.g. ruby:2.6):
jangrewe/gitlab-ci-android
Runner registered successfully. Feel free to start it, but if it's running already the config should be automatically reloaded!

部分 runner 常用命令

1
2
# 注册
gitlab-runner register
1
2
# 注销
gitlab-runner unregister
1
2
# 当前运行
gitlab-runner list
1
2
# 启动
gitlab-runner start
1
2
# 停止
gitlab-runner stop
1
2
# 重启
gitlab-runner restart
1
2
3
4
5
# 查询状态
gitlab-runner status

# 删除无效 runner
gitlab-runner verify --delete

更多参考

修改配置

配置文件 /etc/gitlab-runner/config.toml 手动添加配置 builds_dir 和 cache_dir

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# 默认配置
concurrent = 1
check_interval = 0

[session_server]
session_timeout = 1800

[[runners]]
name = "CI Android Docker"
url = "https://192.168.2.3:8080/"
token = "CsHtxdf8s4-GsfgyrTRa"
executor = "docker"
[runners.custom_build_dir]
[runners.cache]
[runners.cache.s3]
[runners.cache.gcs]
[runners.cache.azure]
[runners.docker]
tls_verify = false
image = "jangrewe/gitlab-ci-android"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
shm_size = 0


# 修改后配置
concurrent = 1
check_interval = 0

[session_server]
session_timeout = 1800

[[runners]]
name = "CI Android Docker"
url = "https://192.168.2.3:8080/"
token = "CsHtxdf8s4-GsfgyrTRa"
executor = "docker"
builds_dir = "/opt/gitlab-runner/builds"
cache_dir = "/opt/gitlab-runner/cache"
[runners.docker]
tls_verify = false
image = "jangrewe/gitlab-ci-android"
privileged = false
disable_entrypoint_overwrite = false
oom_kill_disable = false
disable_cache = false
volumes = ["/cache"]
pull_policy="if-not-present"
shm_size = 0

修改配置 快捷脚本

1
2
# 备份配置文件,防止脚本错误
cp /etc/gitlab-runner/config.toml /etc/gitlab-runner/config.toml.bak
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# -*- coding: UTF-8 -*-
#!/usr/bin/env python
#
# 环 境:Python 3
#
# 快速修改 gitlab 环境配置
#

import os
import platform
import shutil
import toml
import requests
import hashlib
import zipfile

def getFileMd5(filePath):
with open(filePath,'rb') as f:
md5obj = hashlib.md5()
md5obj.update(f.read())
hash = md5obj.hexdigest()

return hash

def unzip_single(src, dest, password):
#解压单个文件到目标文件夹
if password:
password = password.encode()
zf = zipfile.ZipFile(src)
zf.extractall(path=dest, pwd=password)
zf.close()

def unzip_all(src, dest, password=None):
if not os.path.isdir(src):
unzip_single(src, dest, password)
else:
it = os.scandir(src)
for entry in it:
if entry.is_file() and os.path.splitext(entry.name)[1]=='.zip' :
unzip_single(entry.path, dest, password)

def verifyRes(targetDir,remoteRes):
returnValue = False
if not os.path.exists(targetDir):
os.makedirs(targetDir)

srcFile = os.path.join(targetDir,"{0}-{1}.zip".format(remoteRes["name"],remoteRes["md5"]))
hasFile = False
if os.path.exists(srcFile):
hashMd5 = getFileMd5(srcFile)
print("cached,Md5",hashMd5)
if hashMd5 == remoteRes["md5"] or hashMd5 == remoteRes["md5"].lower():
hasFile = True

if not hasFile :
# 全新下载
httpResponse = requests.get(remoteRes["url"])
hashMd5 = None
if httpResponse.status_code == requests.codes.ok:
with open(srcFile,"wb") as f:
f.write(httpResponse.content)
hashMd5 = getFileMd5(srcFile)
print("new,Md5",hashMd5)
if hashMd5 == remoteRes["md5"] or hashMd5 == remoteRes["md5"].lower():
hasFile = True
if hasFile and zipfile.is_zipfile(srcFile) :
unzip_all(srcFile,targetDir)
returnValue = True
print("解压成功",srcFile)
return returnValue


if __name__ == '__main__':

dir = os.path.abspath(os.path.dirname(__file__))

source = None
osName = platform.system()
if osName == "Windows":
# 测试代码
source = os.path.join(dir,"gitlab-runner-config.toml")
elif osName == "Linux":
source = "/etc/gitlab-runner/config.toml"

if source is None:
print("Source config is none")
exit(1)
elif not os.access(source, os.F_OK):
print("Source config not exist")
exit(1)
elif not os.access(source, os.R_OK):
print("Source config can't read")
exit(1)
elif not os.access(source, os.W_OK):
print("Source config can't write")
exit(1)

target = os.path.join(dir,"config.toml")

# print("{0}".format(dir))

try:
shutil.copyfile(source, target)
except IOError as e:
print("Unable to copy file. %s" % e)
exit(1)
except:
print("Unexpected error:", sys.exc_info())
exit(1)

targetRunnerDefaultName = "android-runner-book"

targetRunnerName = input("Enter target runner name ({0}): ".format(targetRunnerDefaultName))
if len(targetRunnerName) == 0 :
targetRunnerName = targetRunnerDefaultName


if os.path.exists(target) :
hasChanged = False
configs = toml.load(target)

hostGradleHomeDir = None
hostAndroidSdkDir = None
if osName == "Windows":
# 测试代码
hostGradleHomeDir = os.path.join(dir,"gradle-home")
hostAndroidSdkDir = os.path.join(dir,"android-sdk")
elif osName == "Linux":
hostGradleHomeDir = "/opt/gitlab-runner/gradle-home"
hostAndroidSdkDir = "/opt/gitlab-runner/android-sdk"

# 测试代码
# shutil.rmtree(hostGradleHomeDir)
remoteGradleRes = {"url":"https://192.168.2.25:456/gradle-5.6.4-6.1.1.zip","md5":"A8CDFB46BE21A98EBFFAC9174276CF47","name":"xGradle-5.6.4-6.1.1"}
remoteAndroidSdkRes = {"url":"https://192.168.2.25:456/sdk-29.0.3.zip","md5":"BFA11A9E09C5B7525EFDD9627B2604FE","name":"xAndroidSdk"}
# remoteAndroidSdkRes = {"url":"https://192.168.2.25:456/sdk-29.0.3-with-ndk-21.0.3.zip","md5":"4D6DB607F10361C5EA2444CF137B446C","name":"xAndroidSdkWithNDK"}
hasLocalGradleRes = False
hasLocalAndroidSdkRes = False

for runnerConfig in configs["runners"]:
if runnerConfig["name"] == targetRunnerName:
# print(runnerConfig)
hasChanged = True
# 编译运行目录
runnerConfig["builds_dir"] = "/opt/gitlab-runner/builds"
runnerConfig["cache_dir"] = "/opt/gitlab-runner/cache"
# 禁用 CI 配置.自定义目录
runnerConfig["custom_build_dir"]["enabled"] = False

if "cache" in runnerConfig :
# 'cache': {'s3': {}, 'gcs': {}, 'azure': {}}
del runnerConfig["cache"]

if runnerConfig["executor"] == "docker" and "docker" in runnerConfig:
dockerConfig = runnerConfig["docker"]
runnerDockerVolumes = None
if "volumes" not in dockerConfig :
runnerDockerVolumes = []
else:
runnerDockerVolumes = dockerConfig["volumes"]
# 追加补充挂载 Host 主机目录到 gitlab-runner 的 docker 配置
volumeOfGradle = "{0}:/android/gradle:rw".format(hostGradleHomeDir)
if volumeOfGradle not in runnerDockerVolumes:
runnerDockerVolumes.append(volumeOfGradle)
hasLocalGradleRes = False
else:
hasLocalGradleRes = True

volumeOfAndroidSdk = "{0}:/android/sdk:rw".format(hostAndroidSdkDir)
if volumeOfAndroidSdk not in runnerDockerVolumes:
runnerDockerVolumes.append(volumeOfAndroidSdk)
hasLocalAndroidSdkRes = False
else:
hasLocalAndroidSdkRes = True
# print(runnerDockerVolumes)

if not hasLocalGradleRes:
hasLocalGradleRes=verifyRes(hostGradleHomeDir,remoteGradleRes)
if not hasLocalAndroidSdkRes:
hasLocalAndroidSdkRes=verifyRes(hostAndroidSdkDir,remoteAndroidSdkRes)

if hasChanged :
with open(target, 'w') as f:
r = toml.dump(configs, f)
# print(r)
print("配置已更新到:",target)