Jenkins for native

專案環境 cordova + native 混合專案

透過docker 啟動 Jenkins Server,在docker-compose.yml改TimeZone

  • .env檔案

    1
    JENKINS_DATA=/Users/yourName/Downloads/docker_volumes/JENKINS_HOME/
  • docker-compose.yml描述檔案

    • volumes對應位置 .env檔案 設定本機位置
    • environment可以改時區
      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      version: "3"
      services:
      jenkins_server:
      image: jenkins
      ports:
      - "50080:8080"
      - "50000:50000"
      volumes:
      - ${JENKINS_DATA}:/var/jenkins_home
      container_name: hijenkins
      environment:
      TZ: "Asia/Taipei"
  • 應用於cordova專案 人員必須手動需入keystore_pwd才能建置出上架版本

    • parameters 設計UI給使用者輸入
    • 紀錄打包過後的成品

      1
      2
      3
      4
      options {
      skipDefaultCheckout(true)
      buildDiscarder(logRotator(numToKeepStr: '7’)) // 只記錄前七次,其他都丟棄。(有其它用法)
      }
    • 主要是將輸入的密碼隱藏起來,如此在console log中不會顯示密碼(需要安裝plugin)

      1
      2
      3
      wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: 'keystore_pwd', var: 'KEYSTORE_PWD']]]) {      
      echo "KEYSTORE_PWD is ${params.KEYSTORE_PWD}"
      }
    • ARCHIVE SUCCEEDED EXPORT SUCCEEDED **
      為了解決iOS 自動打包的錯誤 errSecInternalComponent 要先輸入開機密碼將keychain打開 參考資料

      1
      sh "security unlock-keychain -p ${params.KEYSTORE_PWD} /Users/devilcry/Library/Keychains/login.keychain"

完整程式碼

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
properties([
parameters([

choice(name: 'DEPLOY_TARGET', description: 'The target device', choices: 'iOS\nANDROID'),
password(name: 'KEYSTORE_PWD', defaultValue: '', description: 'Android:keystore_pwd,iOS:keychain_pwd'),
string(name: 'KEY_ALIAS', defaultValue: '', description: 'input KEY_ALIAS(ANDROID only)'),
password(name: 'KEY_PWD', defaultValue: '', description: 'Android only input'),
booleanParam(name: "ONLY_WWW", defaultValue: true, description: '' ),
string(name: 'VERSION', defaultValue: '', description: 'input www version'),
string(name: 'BRANCH', defaultValue: '', description: 'input Branch'),

])
])

pipeline {
agent {
label {
label 'Build_Slave'
}
}

environment {
SDK_PATH="/Users/yourName/Library/Android/sdk/build-tools/26.0.1/"
PATH = "$PATH:$SDK_PATH"
}

options {
skipDefaultCheckout(true)
buildDiscarder(logRotator(numToKeepStr: '7'))
}

stages {
stage("Print") {
steps {
echo "DEPLOY_TARGET: ${params.DEPLOY_TARGET}"
echo "ONLY_WWW: ${params.ONLY_WWW}"
echo "VERSION: ${params.VERSION}"
echo "BRANCH: ${params.BRANCH}"

wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: 'keystore_pwd', var: 'KEYSTORE_PWD'],[password: 'key_pwd', var: 'KEY_PWD']]]) {
echo "KEYSTORE_PWD is ${params.KEYSTORE_PWD}"
echo "KEY_PWD is ${params.KEY_PWD}"
}

}
}
stage("Checkout") {
steps {
checkout([
$class: 'SubversionSCM',
additionalCredentials: [],
excludedCommitMessages: '',
excludedRegions: '',
excludedRevprop: '',
excludedUsers: '',
filterChangelog: false,
ignoreDirPropChanges: false,
includedRegions: '',
locations: [[credentialsId: 'svn',
depthOption: 'infinity',
ignoreExternalsOption: true,
local: 'svn_source',
remote: "https://yourgithub.com"]],
workspaceUpdater: [$class: 'UpdateUpdater']
])
}
}
stage("Node Prepare") {
steps {
dir('svn_source') {
script {
sh("node prepare -r ${params.VERSION} -o -z")
}
}
}
}
stage("Ouptput www.zip") {
steps {
script{
dir('svn_source/resource') {
sh("mkdir ${BUILD_TAG}")

if (params.DEPLOY_TARGET == "iOS"){
sh("rm www_a*.zip")
} else if (params.DEPLOY_TARGET == "ANDROID"){
sh("rm www_i*.zip")
}

sh("mv *.zip ./${BUILD_TAG}")
archiveArtifacts artifacts: '**/${BUILD_TAG}/*.zip', fingerprint: true
sh "rm -rf ./*"
}
}
}
}

stage("Build Native") {
steps {
script {
if (params.ONLY_WWW == true) {

}else {
if (params.DEPLOY_TARGET == "ANDROID") {
dir('svn_source/android/complete_prod') {

sh "./gradlew clean assembleRelease"


sh "zipalign -f -v 4 ./build/outputs/apk/complete_prod-release-unsigned.apk ./build/outputs/apk/unsigned.apk"

wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: 'keystore_pwd', var: 'KEYSTORE_PWD'],[password: 'key_pwd', var: 'KEY_PWD']]]) {

sh "apksigner sign --ks ../Rock.KEYSTORE --ks-key-alias ${params.KEY_ALIAS} --ks-pass pass:${params.KEYSTORE_PWD} --key-pass pass:${params.KEY_PWD} --out ./build/outputs/apk/complete-prod_${BUILD_TAG}.apk ./build/outputs/apk/unsigned.apk"

}

archiveArtifacts artifacts: '**/apk/complete-prod_${BUILD_TAG}.apk', fingerprint: true
sh "rm -rf build"
}
}else if (params.DEPLOY_TARGET == "iOS"){
dir('svn_source/ios/TCBBank/TCBMobileBank'){
sh("mkdir -p ht_build/${BUILD_TAG}")

wrap([$class: 'MaskPasswordsBuildWrapper', varPasswordPairs: [[password: 'keystore_pwd', var: 'KEYSTORE_PWD']]]) {

sh "security unlock-keychain -p ${params.KEYSTORE_PWD} /Users/devilcry/Library/Keychains/login.keychain"

}

echo "[ Build Info ], STAGING, Archive"
sh "xcodebuild archive -scheme TCBMobileBank -target TCBMobileBank -archivePath ./ht_build/${BUILD_TAG}.xcarchive"

echo "[ Build Info ], STAGING, Export Archive"
sh "xcodebuild -exportArchive -archivePath ./ht_build/${BUILD_TAG}.xcarchive -exportOptionsPlist ./exportOptions_Prod.plist -exportPath ./ht_build/${BUILD_TAG}"

archiveArtifacts artifacts: '**/ht_build/${BUILD_TAG}/*.ipa', fingerprint: true

sh "rm -rf ht_build"
}
}
}
}
}
}
}
}