build.groovy 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. // ==============================
  2. // Pipeline config constants
  3. // ==============================
  4. def GIT_URL = 'http://8.134.139.102:10880/m1ro/gami-web'
  5. def GIT_BRANCH = 'main'
  6. // Deployment nodes list.
  7. def NODES = ['10.0.0.12']
  8. def REMOTE_USER = 'ubuntu'
  9. def REMOTE_DIR = '/home/ubuntu/gami-web-runtime'
  10. def PM2_APP = 'gami'
  11. // Required when NODES is not empty.
  12. def SSH_CREDENTIALS_ID = 'prod-web-server'
  13. // Jenkins credentials id of dotenv file (.env). Recommended type: "Secret file"
  14. def DOTENV_CREDENTIALS_ID = 'prod-web-env'
  15. // Skip coscli upload step inside yarn build:prod
  16. def SKIP_COS_UPLOAD = false
  17. pipeline {
  18. agent {
  19. docker {
  20. image 'node:22'
  21. args '-u root:root -v /usr/local/bin/coscli:/usr/local/bin/coscli:ro'
  22. }
  23. }
  24. options {
  25. timestamps()
  26. skipDefaultCheckout(true)
  27. }
  28. environment {
  29. CI = 'true'
  30. }
  31. stages {
  32. stage('Checkout') {
  33. steps {
  34. checkout([
  35. $class: 'GitSCM',
  36. branches: [[name: "*/${GIT_BRANCH}"]],
  37. userRemoteConfigs: [[url: GIT_URL]]
  38. ])
  39. }
  40. }
  41. stage('Install') {
  42. steps {
  43. sh '''
  44. set -eu
  45. node --version
  46. if [ ! -x /usr/local/bin/coscli ]; then
  47. echo "[WARN] /usr/local/bin/coscli not found or not executable on docker host mount. coscli-related steps may fail."
  48. else
  49. /usr/local/bin/coscli --version || true
  50. fi
  51. if ! command -v yarn >/dev/null 2>&1; then
  52. if command -v corepack >/dev/null 2>&1; then
  53. corepack enable
  54. fi
  55. fi
  56. yarn --version
  57. yarn install --frozen-lockfile
  58. '''
  59. }
  60. }
  61. stage('Prepare Env') {
  62. when {
  63. expression { return (DOTENV_CREDENTIALS_ID ?: '').trim() }
  64. }
  65. steps {
  66. withCredentials([file(credentialsId: DOTENV_CREDENTIALS_ID, variable: 'DOTENV_FILE')]) {
  67. sh '''
  68. set -eu
  69. cp "$DOTENV_FILE" .env
  70. chmod 600 .env || true
  71. '''
  72. }
  73. }
  74. }
  75. stage('Build') {
  76. steps {
  77. sh """
  78. set -eu
  79. SKIP_COS_UPLOAD="${SKIP_COS_UPLOAD}" yarn build:prod
  80. test -d .output
  81. """
  82. }
  83. }
  84. stage('Archive') {
  85. steps {
  86. sh '''
  87. set -eu
  88. rm -f gami-web-runtime.tgz
  89. tar -czf gami-web-runtime.tgz .output ecosystem.config.cjs
  90. '''
  91. archiveArtifacts artifacts: 'gami-web-runtime.tgz, ecosystem.config.cjs, .output/**', fingerprint: true
  92. }
  93. }
  94. stage('Deploy') {
  95. when {
  96. expression { return (NODES ?: []).size() > 0 }
  97. }
  98. steps {
  99. script {
  100. def nodes = (NODES ?: [])
  101. .collect { "${it}".trim() }
  102. .findAll { it }
  103. .unique()
  104. if (nodes.isEmpty()) {
  105. echo 'No nodes provided, skipping deploy.'
  106. return
  107. }
  108. if (!(SSH_CREDENTIALS_ID ?: '').trim()) {
  109. error('SSH_CREDENTIALS_ID is required for deploy stage.')
  110. }
  111. sshagent(credentials: [SSH_CREDENTIALS_ID]) {
  112. nodes.each { node ->
  113. def deployThisNode = input(
  114. message: "Deploy to node: ${node} ?",
  115. ok: 'Deploy',
  116. parameters: [
  117. booleanParam(
  118. name: 'CONFIRM_DEPLOY',
  119. defaultValue: false,
  120. description: "Check to confirm deploying to ${node}"
  121. )
  122. ]
  123. ) as boolean
  124. if (!deployThisNode) {
  125. echo "Skipped node: ${node}"
  126. return
  127. }
  128. sh """
  129. set -eu
  130. ssh -o StrictHostKeyChecking=no ${REMOTE_USER}@${node} 'mkdir -p ${REMOTE_DIR}'
  131. scp -o StrictHostKeyChecking=no gami-web-runtime.tgz ${REMOTE_USER}@${node}:${REMOTE_DIR}/
  132. if [ -f .env ]; then
  133. scp -o StrictHostKeyChecking=no .env ${REMOTE_USER}@${node}:${REMOTE_DIR}/
  134. fi
  135. ssh -o StrictHostKeyChecking=no ${REMOTE_USER}@${node} '
  136. set -eu
  137. cd ${REMOTE_DIR}
  138. rm -rf .output
  139. tar -xzf gami-web-runtime.tgz
  140. if [ -f .env ]; then
  141. set -a
  142. . ./.env
  143. set +a
  144. fi
  145. pm2 restart ${PM2_APP} --update-env
  146. '
  147. """
  148. }
  149. }
  150. }
  151. }
  152. }
  153. }
  154. }