dev #39
35
expenses_manager/Jenkinsfile
vendored
35
expenses_manager/Jenkinsfile
vendored
@ -4,8 +4,8 @@ pipeline {
|
|||||||
agent none
|
agent none
|
||||||
|
|
||||||
environment {
|
environment {
|
||||||
// Jenkins has no Docker daemon, so everything Docker-related happens on
|
// Everything Docker-related happens on the NAS over SSH: Jenkins has no
|
||||||
// the NAS over SSH. Absolute paths are required: the remote
|
// daemon of its own. Absolute paths are required — the remote
|
||||||
// non-interactive PATH does not include /usr/local/bin.
|
// non-interactive PATH does not include /usr/local/bin.
|
||||||
NAS_HOST = '192.168.1.140'
|
NAS_HOST = '192.168.1.140'
|
||||||
NAS_USER = 'jenkins-ci'
|
NAS_USER = 'jenkins-ci'
|
||||||
@ -26,8 +26,7 @@ pipeline {
|
|||||||
|
|
||||||
stages {
|
stages {
|
||||||
|
|
||||||
// Nested stages share one agent allocation, so the venv built in the
|
// Nested stages share one agent allocation.
|
||||||
// first stage is still there for the ones that follow.
|
|
||||||
stage('CI') {
|
stage('CI') {
|
||||||
agent any
|
agent any
|
||||||
options { timeout(time: 30, unit: 'MINUTES') }
|
options { timeout(time: 30, unit: 'MINUTES') }
|
||||||
@ -67,7 +66,6 @@ pipeline {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catches models changed without generating the migration.
|
|
||||||
// Catches models changed without generating the migration.
|
// Catches models changed without generating the migration.
|
||||||
stage('Check migrations') {
|
stage('Check migrations') {
|
||||||
steps {
|
steps {
|
||||||
@ -112,11 +110,13 @@ pipeline {
|
|||||||
}
|
}
|
||||||
post {
|
post {
|
||||||
always {
|
always {
|
||||||
|
// allowEmptyResults: false is deliberate. A build where
|
||||||
|
// pytest died before collecting anything produces no XML,
|
||||||
|
// and that must fail rather than pass quietly.
|
||||||
junit allowEmptyResults: false, testResults: 'junit.xml'
|
junit allowEmptyResults: false, testResults: 'junit.xml'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
stage('Smoke test image') {
|
stage('Smoke test image') {
|
||||||
steps {
|
steps {
|
||||||
@ -176,8 +176,8 @@ pipeline {
|
|||||||
if (rc != 0) {
|
if (rc != 0) {
|
||||||
// Printing the plan also proves the database is reachable.
|
// Printing the plan also proves the database is reachable.
|
||||||
// If the non-zero status above was a connection failure
|
// If the non-zero status above was a connection failure
|
||||||
// rather than pending migrations, this fails loudly
|
// rather than pending migrations, this fails loudly instead
|
||||||
// instead of asking for approval on a false premise.
|
// of asking for approval on a false premise.
|
||||||
sh '''
|
sh '''
|
||||||
SHA=$(echo "${GIT_COMMIT}" | cut -c1-7)
|
SHA=$(echo "${GIT_COMMIT}" | cut -c1-7)
|
||||||
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
||||||
@ -217,8 +217,8 @@ pipeline {
|
|||||||
sh '''
|
sh '''
|
||||||
SHA=$(echo "${GIT_COMMIT}" | cut -c1-7)
|
SHA=$(echo "${GIT_COMMIT}" | cut -c1-7)
|
||||||
|
|
||||||
# Always back up, even with no migrations pending: this is
|
# Always back up, even with no migrations pending: this is the
|
||||||
# the restore point for this particular deployment.
|
# restore point for this particular deployment.
|
||||||
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} "sudo ${NAS_BACKUP}"
|
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} "sudo ${NAS_BACKUP}"
|
||||||
|
|
||||||
# Migrate with the new image before the running container is
|
# Migrate with the new image before the running container is
|
||||||
@ -230,10 +230,9 @@ pipeline {
|
|||||||
--env-file ${APP_ENV} \
|
--env-file ${APP_ENV} \
|
||||||
${IMAGE}:${SHA} python manage.py migrate --noinput"
|
${IMAGE}:${SHA} python manage.py migrate --noinput"
|
||||||
|
|
||||||
# Point compose at the image that was just tested, then swap
|
# Point compose at the image that was just tested, then swap the
|
||||||
# the container. Writing the tag to .env leaves a readable
|
# container. Writing the tag to .env leaves a readable record of
|
||||||
# record of what is deployed, and makes rollback a one-line
|
# what is deployed and makes rollback a one-line edit.
|
||||||
# edit plus "docker-compose up -d web".
|
|
||||||
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
||||||
"echo WEB_IMAGE=${IMAGE}:${SHA} > ${COMPOSE_DIR}/.env \
|
"echo WEB_IMAGE=${IMAGE}:${SHA} > ${COMPOSE_DIR}/.env \
|
||||||
&& cd ${COMPOSE_DIR} \
|
&& cd ${COMPOSE_DIR} \
|
||||||
@ -241,10 +240,10 @@ pipeline {
|
|||||||
'''
|
'''
|
||||||
|
|
||||||
script {
|
script {
|
||||||
// The Host header must match ALLOWED_HOSTS or Django answers
|
// The Host header must match ALLOWED_HOSTS or Django answers 400
|
||||||
// 400 regardless of health. A 301 is the expected reply here:
|
// regardless of health. A 301 is expected: SECURE_SSL_REDIRECT
|
||||||
// SECURE_SSL_REDIRECT sends plain HTTP to HTTPS, and reaching
|
// sends plain HTTP to HTTPS, and reaching that redirect already
|
||||||
// that redirect already proves the app processed the request.
|
// proves the app processed the request.
|
||||||
def code = sh(returnStdout: true, script: '''
|
def code = sh(returnStdout: true, script: '''
|
||||||
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
ssh ${SSH_OPTS} ${NAS_USER}@${NAS_HOST} \
|
||||||
"sleep 10 && curl -s -o /dev/null -w '%{http_code}' \
|
"sleep 10 && curl -s -o /dev/null -w '%{http_code}' \
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user