pipeline {
agent { label 'mac' }
environment {
UNITY_VER = '6000.0.26f1'
UNITY_PATH = "/Applications/Unity/Hub/Editor/${UNITY_VER}/Unity.app/Contents/MacOS/Unity"
UNITY_BUILD_AAB = 'false'
}
triggers {
pollSCM(`* * * * *')
}
stages {
stage('Init Project Name') {
steps {
script {
def repoName = params.REPO_URL.tokenize('/').last().replacegit', ('.'')
env.PROJECT_DIR = repoName
env.PROJECT_NAME = repoName.replaceFirst(/-client$/, '')
env.LOGS_DIR = "${env.PROJECT_DIR}/Logs"
env.BUILD_OUTPUT_DIR = "${env.PROJECT_DIR}/Builds/android/"
echo "[INFO] Project Name: ${env.PROJECT_DIR}"
}
}
}
stage('Unity Version Check') {
steps {
sh '"$UNITY_PATH" -version'
}
}
stage('Build Unity Android') {
steps {
dir("${env.PROJECT_DIR}/${env.PROJECT_NAME}") {
withCredentials([
string(credentialsId: 'keystore_pass', variable: 'KEYSTORE_PASS'),
string(credentialsId: 'key_alias', variable: 'KEY_ALIAS'),
string(credentialsId: 'key_alias_pass', variable: 'KEY_ALIAS_PASS')
]) {
script {
def buildName = getBuildName()
def logPath = "${env.WORKSPACE}/${env.LOGS_DIR}/${buildName}.log"
def apkPath = "${env.WORKSPACE}/${env.BUILD_OUTPUT_DIR}/${buildName}.apk"
def keystorePath = "${env.WORKSPACE}/${env.PROJECT_DIR}/${env.PROJECT_NAME}.keystore"
env.APK_PATH = apkPath
env.LOG_PATH = logPath
withEnv([
"UNITY_BUILD_PATH=${apkPath}",
"UNITY_BUILD_AAB=${env.UNITY_BUILD_AAB}",
"KEYSTORE_PATH=${keystorePath}",
"KEYSTORE_PASS=${env.KEYSTORE_PASS}",
"KEY_ALIAS=${env.KEY_ALIAS}",
"KEY_ALIAS_PASS=${env.KEY_ALIAS_PASS}"
]) {
sh """
mkdir -p "${env.WORKSPACE}/${env.LOGS_DIR}"
ln -sf "${logPath}" "${env.WORKSPACE}/${env.LOGS_DIR}/build_latest.log"
"${env.UNITY_PATH}" \
-batchmode \
-nographics \
-projectPath "${env.WORKSPACE}/${env.PROJECT_DIR}/${env.PROJECT_NAME}" \
-executeMethod AndroidBuilder.BuildAndroid \
-quit \
-logFile "${logPath}" \
-buildTarget android
"""
}
if (!fileExists(apkPath)) {
error "[ERROR] APK build failed: ${apkPath} not found"
}
}
}
}
}
}
stage('Upload to S3') {
steps {
withCredentials([
[$class: 'AmazonWebServicesCredentialsBinding', credentialsId: 'AWS_CREDENTIALS']
]) {
script {
def bucketName = "msg-game"
def folderName = env.PROJECT_NAME
def region = "ap-northeast-2"
def s3Path = "s3://${bucketName}/${folderName}/android/"
def apkFile = env.APK_PATH
def fileName = apkFile.tokenize('/')[-1]
def s3Url = "<https://$>{bucketName}.s3.${region}.amazonaws.com/${folderName}/android/${fileName}"
sh """
export PATH=/usr/local/bin:/opt/homebrew/bin:\$PATH
if ! aws s3api head-bucket --bucket "${bucketName}" 2>/dev/null; then
echo "[INFO] Bucket does not exist. Creating..."
aws s3api create-bucket \
--bucket "${bucketName}" \
--region ${region} \
--create-bucket-configuration LocationConstraint=${region}
else
echo "[INFO] Bucket already exists."
fi
aws s3 cp "${apkFile}" "${s3Path}" \
--region ${region}
"""
env.S3_URL = s3Url
echo "[INFO] S3 URL: ${env.S3_URL}"
}
}
}
}
}
post {
success {
script {
sendSlack("success", "#36a64f")
}
}
failure {
script {
sendSlack("failure", "#FF0000")
}
}
}
}
def getBuildName() {
def timestamp = sh(script: "date +\"%Y%m%d_%H%M%S\"", returnStdout: true).trim()
def gitHash = ''
def gitTag = ''
dir(env.PROJECT_DIR) {
gitHash = sh(script: "git rev-parse --short HEAD", returnStdout: true).trim()
gitTag = sh(script: "git describe --tags --abbrev=0 2>/dev/null || echo no-tag", returnStdout: true).trim()
}
return "app_${gitTag}_${gitHash}_${timestamp}"
}
def sendSlack(String status, String color) {
def title = (status == "success") ? "✅ *Unity Android 빌드 성공*" : "❌ *Unity Android 빌드 실패*"
def logFile = "${env.WORKSPACE}/${env.LOGS_DIR}/build_latest.log"
def curlBody = """{
"text": "${title}",
"attachments": [{
"color": "${color}",
"fields": [
{"title": "Project", "value": "${env.PROJECT_NAME}", "short": true},
{"title": "Job", "value": "${env.JOB_NAME} #${env.BUILD_NUMBER}", "short": true},
{"title": "APK", "value": "${env.APK_PATH}", "short": false},
{"title": "Log", "value": "${logFile}", "short": false},
{"title": "S3 Download", "value": "${env.S3_URL}", "short": false}
]
}]
}"""
withCredentials([string(credentialsId: 'SLACK_WEBHOOK_URL', variable: 'SLACK_URL')]) {
sh(script: '''#!/bin/bash
curl -X POST -H 'Content-type: application/json' --data "${curlBody}" "$SLACK_URL"
''')
}
}