Updating automation CICD #36
69
expenses_manager/Jenkinsfile
vendored
69
expenses_manager/Jenkinsfile
vendored
@ -2,18 +2,30 @@ pipeline {
|
||||
agent any
|
||||
|
||||
environment {
|
||||
// settings.py demands SECRET_KEY unless DEBUG is exactly "True".
|
||||
// A throwaway value lets CI run with DEBUG unset — that is, False, as
|
||||
// in production — instead of falling back to the insecure dev key.
|
||||
// DEBUG=True keeps settings.py from enabling SECURE_SSL_REDIRECT, which
|
||||
// makes Django's test client receive a 301 on every request.
|
||||
DEBUG = 'True'
|
||||
SECRET_KEY = 'ci-only-value-never-used-in-production'
|
||||
DJANGO_SETTINGS_MODULE = 'expenses_manager.settings'
|
||||
PYTHONUNBUFFERED = '1'
|
||||
|
||||
// Jenkins has no Docker daemon, so images are built on the NAS over SSH.
|
||||
// Absolute paths are required: the remote non-interactive PATH is
|
||||
// /usr/bin:/bin:/usr/sbin:/sbin and does not include /usr/local/bin.
|
||||
NAS_HOST = '192.168.1.140'
|
||||
NAS_USER = 'jenkins-ci'
|
||||
NAS_DOCKER = '/usr/local/bin/docker'
|
||||
CI_DIR = '/volume1/docker/ci/expenses_manager'
|
||||
SSH_OPTS = '-o StrictHostKeyChecking=accept-new'
|
||||
|
||||
// Deliberately not "finanzas-web": that name belongs to the image
|
||||
// docker-compose builds for production, and CI must never overwrite it.
|
||||
IMAGE = 'expenses-manager-ci'
|
||||
}
|
||||
|
||||
options {
|
||||
buildDiscarder(logRotator(numToKeepStr: '30'))
|
||||
timeout(time: 20, unit: 'MINUTES')
|
||||
timeout(time: 30, unit: 'MINUTES')
|
||||
}
|
||||
|
||||
stages {
|
||||
@ -48,13 +60,60 @@ pipeline {
|
||||
'''
|
||||
}
|
||||
}
|
||||
|
||||
stage('Build image') {
|
||||
steps {
|
||||
sshagent(credentials: ['nas-ssh']) {
|
||||
sh '''
|
||||
SHA=$(echo "${GIT_COMMIT}" | cut -c1-7)
|
||||
TAG=$(echo "${BRANCH_NAME}" | tr '/' '-')
|
||||
|
||||
# Ship the workspace that was just tested, rather than
|
||||
# cloning again on the NAS: what gets built is then
|
||||
# provably the same code the tests ran against.
|
||||
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
||||
"rm -rf ${CI_DIR} && mkdir -p ${CI_DIR}"
|
||||
|
||||
tar -czf - --exclude=./expenses_manager/venv \
|
||||
--exclude=./.git . \
|
||||
| ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
||||
"tar -xzf - -C ${CI_DIR}"
|
||||
|
||||
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
||||
"cd ${CI_DIR} && sudo ${NAS_DOCKER} build \
|
||||
-t ${IMAGE}:${SHA} -t ${IMAGE}:${TAG} ."
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// A successful build only proves the Dockerfile is syntactically sound.
|
||||
// Running Django's own checks inside the image proves it can actually
|
||||
// start: settings load, middleware resolves, static files are collected.
|
||||
stage('Smoke test image') {
|
||||
steps {
|
||||
sshagent(credentials: ['nas-ssh']) {
|
||||
sh '''
|
||||
SHA=$(echo "${GIT_COMMIT}" | cut -c1-7)
|
||||
|
||||
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
||||
"sudo ${NAS_DOCKER} run --rm \
|
||||
-e SECRET_KEY=smoke-test-only \
|
||||
-e DEBUG=False \
|
||||
-e ALLOWED_HOSTS=localhost \
|
||||
-e DB_ENGINE=sqlite3 \
|
||||
${IMAGE}:${SHA} python manage.py check"
|
||||
'''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
post {
|
||||
always {
|
||||
// allowEmptyResults: false is deliberate. A build where pytest died
|
||||
// before collecting anything produces no XML, and that must fail
|
||||
// rather than pass quietly — as happened for months in 2026.
|
||||
// rather than pass quietly.
|
||||
junit allowEmptyResults: false, testResults: 'expenses_manager/junit.xml'
|
||||
}
|
||||
failure {
|
||||
|
||||
Loading…
Reference in New Issue
Block a user