| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173 |
- // ==============================
- // Pipeline config constants
- // ==============================
- def GIT_URL = 'http://8.134.139.102:10880/m1ro/gami-web'
- def GIT_BRANCH = 'main'
- // Deployment nodes list.
- def NODES = ['10.0.0.12']
- def REMOTE_USER = 'ubuntu'
- def REMOTE_DIR = '/home/ubuntu/gami-web-runtime'
- def PM2_APP = 'gami'
- // Required when NODES is not empty.
- def SSH_CREDENTIALS_ID = 'prod-web-server'
- // Jenkins credentials id of dotenv file (.env). Recommended type: "Secret file"
- def DOTENV_CREDENTIALS_ID = 'prod-web-env'
- // Skip coscli upload step inside yarn build:prod
- def SKIP_COS_UPLOAD = false
- pipeline {
- agent {
- docker {
- image 'node:22'
- args '-u root:root -v /usr/local/bin/coscli:/usr/local/bin/coscli:ro'
- }
- }
- options {
- timestamps()
- skipDefaultCheckout(true)
- }
- environment {
- CI = 'true'
- }
- stages {
- stage('Checkout') {
- steps {
- checkout([
- $class: 'GitSCM',
- branches: [[name: "*/${GIT_BRANCH}"]],
- userRemoteConfigs: [[url: GIT_URL]]
- ])
- }
- }
- stage('Install') {
- steps {
- sh '''
- set -eu
- node --version
- if [ ! -x /usr/local/bin/coscli ]; then
- echo "[WARN] /usr/local/bin/coscli not found or not executable on docker host mount. coscli-related steps may fail."
- else
- /usr/local/bin/coscli --version || true
- fi
- if ! command -v yarn >/dev/null 2>&1; then
- if command -v corepack >/dev/null 2>&1; then
- corepack enable
- fi
- fi
- yarn --version
- yarn install --frozen-lockfile
- '''
- }
- }
- stage('Prepare Env') {
- when {
- expression { return (DOTENV_CREDENTIALS_ID ?: '').trim() }
- }
- steps {
- withCredentials([file(credentialsId: DOTENV_CREDENTIALS_ID, variable: 'DOTENV_FILE')]) {
- sh '''
- set -eu
- cp "$DOTENV_FILE" .env
- chmod 600 .env || true
- '''
- }
- }
- }
- stage('Build') {
- steps {
- sh """
- set -eu
- SKIP_COS_UPLOAD="${SKIP_COS_UPLOAD}" yarn build:prod
- test -d .output
- """
- }
- }
- stage('Archive') {
- steps {
- sh '''
- set -eu
- rm -f gami-web-runtime.tgz
- tar -czf gami-web-runtime.tgz .output ecosystem.config.cjs
- '''
- archiveArtifacts artifacts: 'gami-web-runtime.tgz, ecosystem.config.cjs, .output/**', fingerprint: true
- }
- }
- stage('Deploy') {
- when {
- expression { return (NODES ?: []).size() > 0 }
- }
- steps {
- script {
- def nodes = (NODES ?: [])
- .collect { "${it}".trim() }
- .findAll { it }
- .unique()
- if (nodes.isEmpty()) {
- echo 'No nodes provided, skipping deploy.'
- return
- }
- if (!(SSH_CREDENTIALS_ID ?: '').trim()) {
- error('SSH_CREDENTIALS_ID is required for deploy stage.')
- }
- sshagent(credentials: [SSH_CREDENTIALS_ID]) {
- nodes.each { node ->
- def deployThisNode = input(
- message: "Deploy to node: ${node} ?",
- ok: 'Deploy',
- parameters: [
- booleanParam(
- name: 'CONFIRM_DEPLOY',
- defaultValue: false,
- description: "Check to confirm deploying to ${node}"
- )
- ]
- ) as boolean
- if (!deployThisNode) {
- echo "Skipped node: ${node}"
- return
- }
- sh """
- set -eu
- ssh -o StrictHostKeyChecking=no ${REMOTE_USER}@${node} 'mkdir -p ${REMOTE_DIR}'
- scp -o StrictHostKeyChecking=no gami-web-runtime.tgz ${REMOTE_USER}@${node}:${REMOTE_DIR}/
- if [ -f .env ]; then
- scp -o StrictHostKeyChecking=no .env ${REMOTE_USER}@${node}:${REMOTE_DIR}/
- fi
- ssh -o StrictHostKeyChecking=no ${REMOTE_USER}@${node} '
- set -eu
- cd ${REMOTE_DIR}
- rm -rf .output
- tar -xzf gami-web-runtime.tgz
- if [ -f .env ]; then
- set -a
- . ./.env
- set +a
- fi
- pm2 restart ${PM2_APP} --update-env
- '
- """
- }
- }
- }
- }
- }
- }
- }
|