├── Dockerfile ├── Jenkinsfile └── README.md /Dockerfile: -------------------------------------------------------------------------------- 1 | #https://quay.io/repository/bitriseio/bitrise-base?tab=tags 2 | #Image being leverage as the base image to build Android apps against 3 | FROM quay.io/bitriseio/bitrise-base:latest 4 | 5 | MAINTAINER Tanck 6 | 7 | ENV ANDROID_HOME /opt/android-sdk-linux 8 | 9 | # ------------------------------------------------------ 10 | # --- Install required tools 11 | 12 | RUN apt-get update -qq 13 | 14 | # Base (non android specific) tools 15 | # -> should be added to bitriseio/docker-bitrise-base 16 | 17 | # Dependencies to execute Android builds 18 | RUN dpkg --add-architecture i386 19 | RUN apt-get update -qq 20 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y openjdk-8-jdk libc6:i386 libstdc++6:i386 libgcc1:i386 libncurses5:i386 libz1:i386 21 | 22 | # ------------------------------------------------------ 23 | # --- Download Android SDK tools into $ANDROID_HOME 24 | 25 | RUN cd /opt \ 26 | && wget -q https://dl.google.com/android/repository/sdk-tools-linux-4333796.zip -O android-sdk-tools.zip \ 27 | && unzip -q android-sdk-tools.zip -d ${ANDROID_HOME} \ 28 | && rm android-sdk-tools.zip 29 | 30 | ENV PATH ${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/tools/bin:${ANDROID_HOME}/platform-tools 31 | 32 | # ------------------------------------------------------ 33 | # --- Install Android SDKs and other build packages 34 | 35 | # Other tools and resources of Android SDK 36 | # you should only install the packages you need! 37 | # To get a full list of available options you can use: 38 | RUN sdkmanager --list 39 | 40 | # Accept licenses before installing components, no need to echo y for each component 41 | # License is valid for all the standard components in versions installed from this file 42 | # Non-standard components: MIPS system images, preview versions, GDK (Google Glass) and Android Google TV require separate licenses, not accepted there 43 | RUN yes | sdkmanager --licenses 44 | 45 | # Platform tools 46 | RUN sdkmanager "emulator" "tools" "platform-tools" 47 | 48 | # Setup NDK 49 | ENV ANDROID_NDK_HOME ${ANDROID_HOME}/ndk-bundle 50 | RUN cd /opt \ 51 | && wget -q https://dl.google.com/android/repository/android-ndk-r15c-linux-x86_64.zip -O android-ndk-r15c.zip \ 52 | && unzip -q android-ndk-r15c.zip -d ${ANDROID_NDK_HOME} \ 53 | && mv ${ANDROID_NDK_HOME}/android-ndk-r15c/* ${ANDROID_NDK_HOME} \ 54 | && rm android-ndk-r15c.zip 55 | 56 | # SDKs 57 | # Please keep these in descending order! 58 | # The `yes` is for accepting all non-standard tool licenses. 59 | 60 | # Please keep all sections in descending order! 61 | RUN yes | sdkmanager \ 62 | "platforms;android-28" \ 63 | "build-tools;28.0.3" \ 64 | "platforms;android-27" \ 65 | "build-tools;27.0.3" \ 66 | "platforms;android-26" \ 67 | "build-tools;26.0.2" \ 68 | "system-images;android-25;google_apis;armeabi-v7a" \ 69 | "extras;android;m2repository" \ 70 | "extras;google;m2repository" \ 71 | "extras;google;google_play_services" \ 72 | "extras;m2repository;com;android;support;constraint;constraint-layout;1.0.2" \ 73 | "add-ons;addon-google_apis-google-24" 74 | 75 | # ------------------------------------------------------ 76 | # --- Install Gradle from PPA 77 | 78 | # Gradle PPA 79 | RUN apt-get update \ 80 | && apt-get -y install gradle \ 81 | && gradle -v \ 82 | 83 | # ------------------------------------------------------ 84 | # --- Install Maven 3 from PPA 85 | 86 | RUN apt-get purge maven maven2 \ 87 | && apt-get update \ 88 | && apt-get -y install maven \ 89 | && mvn --version 90 | 91 | # ------------------------------------------------------ 92 | # --- Install additional packages 93 | 94 | # Required for Android ARM Emulator 95 | RUN DEBIAN_FRONTEND=noninteractive apt-get install -y libqt5widgets5 96 | ENV QT_QPA_PLATFORM offscreen 97 | ENV LD_LIBRARY_PATH ${ANDROID_HOME}/tools/lib64:${ANDROID_HOME}/emulator/lib64:${ANDROID_HOME}/emulator/lib64/qt/lib 98 | 99 | # ------------------------------------------------------ 100 | # --- Cleanup and rev num 101 | 102 | # Cleaning 103 | RUN apt-get clean 104 | 105 | # Set gradlew permission 106 | #RUN chmod +x ./gradlew 107 | 108 | ENV BITRISE_DOCKER_REV_NUMBER_ANDROID v2017_12_29_1 109 | CMD bitrise -version 110 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env groovy 2 | 3 | //This JenkinsFile is based on a declarative format 4 | //https://jenkins.io/doc/book/pipeline/#declarative-versus-scripted-pipeline-syntax 5 | def DEPLOY_BRANCH = 'development' 6 | // Do not add the `def` for these fields 7 | XXPROJECT_ID = 974 8 | GITLAB_SERVER_URL = 'http://gitlab.com'// Or your server 9 | 10 | pipeline { 11 | // 默认代理用主机,意味着用Jenkins主机来运行一下块 12 | agent any 13 | options { 14 | // 配置当前branch不支持同时构建,为了避免资源竞争,当一个新的commit到来,会进入排队如果之前的构建还在进行 15 | disableConcurrentBuilds() 16 | // 链接到Gitlab的服务器,用于访问Gitlab一些API 17 | gitLabConnection('Jenkins_CI_CD') 18 | } 19 | environment { 20 | // 配置缓存路径在主机 21 | GRADLE_CACHE = '/tmp/gradle-user-cache' 22 | } 23 | stages { 24 | // 初始化阶段 25 | stage('Setup') { 26 | steps { 27 | // 将初始化阶段修改到这次commit即Gitlab会展示对应的UI 28 | gitlabCommitStatus(name: 'Setup') { 29 | // 通过SLACK工具推送一个通知 30 | notifySlack('STARTED') 31 | echo "Setup Stage Starting. Depending on the Docker cache this may take a few " + 32 | "seconds to a couple of minutes." 33 | echo "${env.BRANCH_NAME} is the branch. Subsequent steps may not run on branches that are not ${DEPLOY_BRANCH}." 34 | script { 35 | cacheFileExist = sh(script: "[ -d ${GRADLE_CACHE} ] && echo 'true' || echo 'false' ", returnStdout: true).trim() 36 | echo 'Current cacheFile is exist : ' + cacheFileExist 37 | // Make dir if not exist 38 | if (cacheFileExist == 'false') sh "mkdir ${GRADLE_CACHE}/ || true" 39 | } 40 | } 41 | } 42 | } 43 | 44 | // 构建阶段 45 | stage('Build') { 46 | agent { 47 | dockerfile { 48 | // 构建的时候指定一个DockerFile,该DockerFile有Android的构建环境 49 | filename 'Dockerfile' 50 | // https://github.com/gradle/gradle/issues/851 51 | args '-v $GRADLE_CACHE/.gradle:$HOME/.gradle --net=host' 52 | } 53 | } 54 | 55 | steps { 56 | gitlabCommitStatus(name: 'Build') { 57 | 58 | script { 59 | echo "Build Stage Starting" 60 | echo "Building all types (debug, release, etc.) with lint checking" 61 | getGitAuthor() 62 | 63 | if (env.BRANCH_NAME == DEPLOY_BRANCH) { 64 | 65 | // TODO : Do some checks on your style 66 | 67 | // https://docs.gradle.org/current/userguide/gradle_daemon.html 68 | sh 'chmod +x gradlew' 69 | // Try with the all build types. 70 | sh "./gradlew build" 71 | } else { 72 | // https://docs.gradle.org/current/userguide/gradle_daemon.html 73 | sh 'chmod +x gradlew' 74 | // Try with the production build type. 75 | sh "./gradlew compileReleaseJavaWithJavac" 76 | } 77 | } 78 | } 79 | 80 | script { 81 | // Only the development branch can be triggered 82 | if (env.BRANCH_NAME == DEPLOY_BRANCH) { 83 | gitlabCommitStatus(name: 'Signature') { 84 | // signing the apks with the platform key 85 | signAndroidApks( 86 | keyStoreId: "XXX", 87 | keyAlias: "XXX", 88 | apksToSign: "**/*.apk", 89 | archiveSignedApks: false, 90 | skipZipalign: true 91 | ) 92 | } 93 | 94 | gitlabCommitStatus(name: 'Deploy') { 95 | script { 96 | echo "Debug finding apks" 97 | // debug statement to show the signed apk's 98 | sh 'find . -name "*.apk"' 99 | 100 | // TODO : Deploy your apk to other place 101 | 102 | //Specific deployment to Production environment 103 | //echo "Deploying to Production environment" 104 | } 105 | } 106 | } 107 | } 108 | } 109 | // This post working on the docker. not on the jenkins of local 110 | post { 111 | // The workspace should be cleaned if the build is failure. 112 | failure { 113 | // notFailBuild : if clean failed that not tell Jenkins failed. 114 | cleanWs notFailBuild: true 115 | } 116 | // The APKs should be deleted when the server is successfully built. 117 | success { 118 | script { 119 | // Only the development branch can be deleted these APKs. 120 | if (env.BRANCH_NAME == DEPLOY_BRANCH) { 121 | cleanWs notFailBuild: true, patterns: [[pattern: '**/*.apk', type: 'INCLUDE']] 122 | } 123 | } 124 | } 125 | } 126 | } 127 | } 128 | 129 | post { 130 | always { deleteDir() } 131 | failure { 132 | addCommentToGitLabMR("\\:negative_squared_cross_mark\\: Jenkins Build \\`FAILURE\\`

Results available at:[[#${env.BUILD_NUMBER} ${env.JOB_NAME}](${env.BUILD_URL})]") 133 | notifySlack('FAILED') 134 | } 135 | success { 136 | addCommentToGitLabMR("\\:white_check_mark\\: Jenkins Build \\`SUCCESS\\`

Results available at:[[#${env.BUILD_NUMBER} ${env.JOB_NAME}](${env.BUILD_URL})]") 137 | notifySlack('SUCCESS') 138 | } 139 | unstable { notifySlack('UNSTABLE') } 140 | changed { notifySlack('CHANGED') } 141 | } 142 | } 143 | 144 | def addCommentToGitLabMR(String commentContent) { 145 | branchHasMRID = sh(script: "curl --header \"PRIVATE-TOKEN: ${env.gitTagPush}\" ${GITLAB_SERVER_URL}/api/v4/projects/${XXPROJECT_ID}/merge_requests?source_branch=${env.BRANCH_NAME} | grep -o 'iid\":[^,]*' | head -n 1 | cut -b 6-", returnStdout: true).trim() 146 | echo 'Current Branch has MR id : ' + branchHasMRID 147 | if (branchHasMRID == '') { 148 | echo "The id of MR doesn't exist on the gitlab. skip the comment on MR" 149 | } else { 150 | // TODO : Should be handled on first time. 151 | TheMRState = sh(script: "curl --header \"PRIVATE-TOKEN: ${env.gitTagPush}\" ${GITLAB_SERVER_URL}/api/v4/projects/${XXPROJECT_ID}/merge_requests?source_branch=${env.BRANCH_NAME} | grep -o 'state\":[^,]*' | head -n 1 | cut -b 9-14", returnStdout: true).trim() 152 | echo 'Current MR state is : ' + TheMRState 153 | if (TheMRState == 'opened') { 154 | sh "curl -d \"id=${XXPROJECT_ID}&merge_request_iid=${branchHasMRID}&body=${commentContent}\" --header \"PRIVATE-TOKEN: ${env.gitTagPush}\" ${GITLAB_SERVER_URL}/api/v4//projects/${XXPROJECT_ID}/merge_requests/${branchHasMRID}/notes" 155 | } else { 156 | echo 'The MR not is opened, skip the comment on MR' 157 | } 158 | } 159 | } 160 | 161 | def pushTag(String gitTagName, String gitTagContent) { 162 | sh "curl -d \"id=${XXPROJECT_ID}&tag_name=${gitTagName}&ref=development&release_description=${gitTagContent}\" --header \"PRIVATE-TOKEN: ${env.gitTagPush}\" ${GITLAB_SERVER_URL}/api/v4/projects/${XXPROJECT_ID}/repository/tags" 163 | } 164 | 165 | //Helper methods 166 | //TODO Probably can extract this into a JenkinsFile shared library 167 | def getGitAuthor() { 168 | def commitSHA = sh(returnStdout: true, script: 'git rev-parse HEAD') 169 | author = sh(returnStdout: true, script: "git --no-pager show -s --format='%an' ${commitSHA}").trim() 170 | echo "Commit author: " + author 171 | } 172 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JenkinsWithDockerInAndroid 2 | --------------------------------------------------------------------------------