// Home AI Assistant — деплой на Linux (Docker). // // Нода: label linux // // Реальный путь репо (не symlink): /srv/storage/disk2/services/Home_assistant // ~/to_services/Home_assistant может быть ссылкой на него. // // Права jenkins (один раз): // sudo usermod -aG docker jenkins // sudo setfacl -m u:jenkins:rx /home/grigo /home/grigo/to_services // sudo setfacl -R -m u:jenkins:rwX /srv/storage/disk2/services/Home_assistant pipeline { agent { label 'linux' } options { buildDiscarder(logRotator(numToKeepStr: '25')) timeout(time: 45, unit: 'MINUTES') disableConcurrentBuilds() timestamps() } parameters { string( name: 'GIT_BRANCH', defaultValue: 'main', description: 'Ветка: git reset --hard origin/' ) string( name: 'DEPLOY_DIR', defaultValue: '/srv/storage/disk2/services/Home_assistant', description: 'Каталог деплоя (.env, data/, docker-compose.yml)' ) string( name: 'BACKEND_HEALTH_URL', defaultValue: 'http://127.0.0.1:8202/api/v1/health', description: 'Healthcheck после деплоя' ) booleanParam( name: 'DOCKER_PULL', defaultValue: true, description: 'docker compose build --pull' ) } environment { GIT_BRANCH = "${params.GIT_BRANCH}" DEPLOY_DIR = "${params.DEPLOY_DIR}" BACKEND_HEALTH_URL = "${params.BACKEND_HEALTH_URL}" DOCKER_PULL = "${params.DOCKER_PULL}" } stages { stage('Preflight') { steps { sh ''' set -euxo pipefail REPO_DIR=$(readlink -f "${DEPLOY_DIR}") echo "REPO_DIR=${REPO_DIR}" command -v docker docker compose version test -d "${REPO_DIR}" test -r "${REPO_DIR}" test -w "${REPO_DIR}" test -f "${REPO_DIR}/.env" test -f "${REPO_DIR}/docker-compose.yml" # git от jenkins: владелец репо — grigo git config --global --add safe.directory "${REPO_DIR}" ''' } } stage('Deploy') { steps { sh ''' set -euxo pipefail REPO_DIR=$(readlink -f "${DEPLOY_DIR}") git config --global --add safe.directory "${REPO_DIR}" cd "${REPO_DIR}" git fetch --prune origin git reset --hard "origin/${GIT_BRANCH}" git clean -fd -e .env -e data -e 'data/**' docker compose build backend docker compose run --rm --no-deps backend \ sh -c 'pip install -q -r requirements-dev.txt && pytest tests/ -q --tb=short' if [ "${DOCKER_PULL}" = "true" ]; then docker compose build --pull else docker compose build fi docker compose up -d docker compose ps ''' } } stage('Healthcheck') { steps { sh ''' set -euxo pipefail for i in $(seq 1 30); do if curl -fsS "${BACKEND_HEALTH_URL}" >/dev/null; then echo "OK: ${BACKEND_HEALTH_URL}" exit 0 fi sleep 2 done echo "Healthcheck failed: ${BACKEND_HEALTH_URL}" exit 1 ''' } } } post { success { echo "Deployed ${DEPLOY_DIR} @ origin/${GIT_BRANCH}" } failure { sh ''' REPO_DIR=$(readlink -f "${DEPLOY_DIR}" 2>/dev/null || echo "${DEPLOY_DIR}") if [ -d "${REPO_DIR}" ] && [ -r "${REPO_DIR}" ]; then cd "${REPO_DIR}" docker compose ps || true docker compose logs --tail=100 backend || true docker compose logs --tail=50 frontend || true else echo "Нет доступа к ${REPO_DIR}" fi ''' } } }