diff --git a/Jenkinsfile b/Jenkinsfile deleted file mode 100644 index a70b6fc..0000000 --- a/Jenkinsfile +++ /dev/null @@ -1,185 +0,0 @@ -pipeline { - agent none - - options { - timestamps() - } - - environment { - CI = 'true' - NODE_OPTIONS = '--max_old_space_size=2048' - APP_VERSION = "1.0.${BUILD_NUMBER}" - DOCKER_BUILDKIT = '1' - } - - stages { - - stage('Init') { - agent any - steps { - script { - env.COMMIT_AUTHOR = sh( - script: "git show -s --format=%an HEAD", - returnStdout: true - ).trim() - - env.COMMIT_SHORT = sh( - script: "git rev-parse --short HEAD", - returnStdout: true - ).trim() - } - } - } - - stage('Backend: lint & test') { - agent { - docker { - image 'python:3.11-slim' - args '-u root' - } - } - steps { - dir('backend') { - sh ''' - set -e - python -m venv .venv - . .venv/bin/activate - pip install --upgrade pip - pip install -r requirements-dev.txt - ruff check app tests - pytest - ''' - } - } - } - - stage('Frontend: check & build') { - agent { - docker { - image 'node:20-slim' - } - } - steps { - dir('frontend') { - sh ''' - set -e - npm install --no-progress --no-audit --prefer-offline - npm run check - npm run build - ''' - } - } - } - - stage('Docker: build images') { - agent any - steps { - sh ''' - set -e - - docker build \ - --build-arg APP_VERSION=${APP_VERSION} \ - --build-arg GIT_COMMIT=${COMMIT_SHORT} \ - --build-arg COMMIT_AUTHOR="${COMMIT_AUTHOR}" \ - --build-arg BUILD_NUMBER=${BUILD_NUMBER} \ - -t cafeteria-backend:latest \ - -t cafeteria-backend:${BUILD_NUMBER} \ - ./backend - - docker build \ - -t cafeteria-frontend:latest \ - -t cafeteria-frontend:${BUILD_NUMBER} \ - ./frontend - ''' - } - } - - stage('Deploy frontend & backend') { - when { - branch 'main' - } - - agent any - environment { - JENKINS_BASE_URL = 'http://jenkins:8080' - JENKINS_JOB_NAME = 'Espetos' - } - steps { - withCredentials([ - usernamePassword( - credentialsId: 'jenkins-api-token', - usernameVariable: 'JENKINS_USER', - passwordVariable: 'JENKINS_TOKEN' - ) - ]) { - sh ''' - set -e - - : "${BACKEND_PORT:?Missing BACKEND_PORT}" - : "${BACKEND_HEALTH_URL:?Missing BACKEND_HEALTH_URL}" - : "${FRONTEND_PORT:?Missing FRONTEND_PORT}" - : "${FRONTEND_HEALTH_URL:?Missing FRONTEND_HEALTH_URL}" - - - # Backend - docker tag cafeteria-backend:latest cafeteria-backend:previous || true - docker rm -f cafeteria-backend 2>/dev/null || true - - docker run -d \ - --name cafeteria-backend \ - -p "$BACKEND_PORT":"$BACKEND_PORT" \ - cafeteria-backend:latest - - sleep 5 - - if ! curl -fs "$BACKEND_HEALTH_URL"; then - echo "Backend failed, rollback" - docker rm -f cafeteria-backend - docker run -d \ - --name cafeteria-backend \ - --network ci-net \ - -e JENKINS_BASE_URL \ - -e JENKINS_JOB_NAME \ - -e JENKINS_USER \ - -e JENKINS_TOKEN \ - -p "$BACKEND_PORT":"$BACKEND_PORT" \ - cafeteria-backend:previous - exit 1 - fi - - # Frontend - docker tag cafeteria-frontend:latest cafeteria-frontend:previous || true - docker rm -f cafeteria-frontend 2>/dev/null || true - - docker run -d \ - --name cafeteria-frontend \ - -p "$FRONTEND_PORT":80 \ - cafeteria-frontend:latest - - sleep 3 - - if ! curl -fs "$FRONTEND_HEALTH_URL"; then - echo "Frontend failed, rollback" - docker rm -f cafeteria-frontend - docker run -d \ - --name cafeteria-frontend \ - -p "$FRONTEND_PORT":80 \ - cafeteria-frontend:previous - exit 1 - fi - ''' - } - } - } - } - - post { - always { - sh ''' - docker image prune -a -f || true - docker builder prune -a -f || true - ''' - cleanWs() - } - } -} diff --git a/Jenkinsfile.cd b/Jenkinsfile.cd new file mode 100644 index 0000000..ee5eeba --- /dev/null +++ b/Jenkinsfile.cd @@ -0,0 +1,199 @@ +pipeline { + agent none + + options { + timestamps() + } + + environment { + NODE_OPTIONS = '--max_old_space_size=2048' + APP_VERSION = "1.0.${BUILD_NUMBER}" + DOCKER_BUILDKIT = '1' + } + + stages { + + stage('Init') { + agent any + when { + branch 'main' + } + steps { + script { + env.COMMIT_AUTHOR = sh( + script: "git show -s --format=%an HEAD", + returnStdout: true + ).trim() + + env.COMMIT_SHORT = sh( + script: "git rev-parse --short HEAD", + returnStdout: true + ).trim() + } + + echo "CD deploy for main (${env.COMMIT_SHORT})" + } + } + + /* ========================= + TESTS + ========================= */ + + stage('Backend: test (main)') { + when { + branch 'main' + } + agent { + docker { + image 'python:3.11-slim' + args '-u root' + } + } + steps { + dir('backend') { + sh ''' + set -e + python -m venv .venv + . .venv/bin/activate + pip install --upgrade pip + pip install -r requirements-dev.txt + pytest + ''' + } + } + } + + stage('Frontend: build (main)') { + when { + branch 'main' + } + agent { + docker { + image 'node:20-slim' + } + } + steps { + dir('frontend') { + sh ''' + set -e + npm install --no-progress --no-audit --prefer-offline + npm run build + ''' + } + } + } + + /* ========================= + DOCKER BUILD + ========================= */ + + stage('Docker: build images') { + when { + branch 'main' + } + agent any + steps { + sh ''' + set -e + + docker build \ + --build-arg APP_VERSION=${APP_VERSION} \ + --build-arg GIT_COMMIT=${COMMIT_SHORT} \ + --build-arg COMMIT_AUTHOR="${COMMIT_AUTHOR}" \ + --build-arg BUILD_NUMBER=${BUILD_NUMBER} \ + -t cafeteria-backend:${BUILD_NUMBER} \ + -t cafeteria-backend:latest \ + ./backend + + docker build \ + -t cafeteria-frontend:${BUILD_NUMBER} \ + -t cafeteria-frontend:latest \ + ./frontend + ''' + } + } + + /* ========================= + DEPLOY + ========================= */ + + stage('Deploy frontend & backend') { + when { + branch 'main' + } + agent any + environment { + JENKINS_BASE_URL = 'http://jenkins:8080' + JENKINS_JOB_NAME = 'Espetos' + } + steps { + withCredentials([ + usernamePassword( + credentialsId: 'jenkins-api-token', + usernameVariable: 'JENKINS_USER', + passwordVariable: 'JENKINS_TOKEN' + ) + ]) { + sh ''' + set -e + + : "${BACKEND_PORT:?Missing BACKEND_PORT}" + : "${BACKEND_HEALTH_URL:?Missing BACKEND_HEALTH_URL}" + : "${FRONTEND_PORT:?Missing FRONTEND_PORT}" + : "${FRONTEND_HEALTH_URL:?Missing FRONTEND_HEALTH_URL}" + + echo "Deploying backend ${BUILD_NUMBER}" + + docker tag cafeteria-backend:latest cafeteria-backend:previous || true + docker rm -f cafeteria-backend 2>/dev/null || true + + docker run -d \ + --name cafeteria-backend \ + -p "$BACKEND_PORT":"$BACKEND_PORT" \ + cafeteria-backend:latest + + sleep 5 + + if ! curl -fs "$BACKEND_HEALTH_URL"; then + echo "Backend failed, rolling back" + docker rm -f cafeteria-backend + docker run -d \ + --name cafeteria-backend \ + -p "$BACKEND_PORT":"$BACKEND_PORT" \ + cafeteria-backend:previous + exit 1 + fi + + echo "Deploying frontend ${BUILD_NUMBER}" + + docker tag cafeteria-frontend:latest cafeteria-frontend:previous || true + docker rm -f cafeteria-frontend 2>/dev/null || true + + docker run -d \ + --name cafeteria-frontend \ + -p "$FRONTEND_PORT":80 \ + cafeteria-frontend:latest + + sleep 3 + + if ! curl -fs "$FRONTEND_HEALTH_URL"; then + echo "Frontend failed, rolling back" + docker rm -f cafeteria-frontend + docker run -d \ + --name cafeteria-frontend \ + -p "$FRONTEND_PORT":80 \ + cafeteria-frontend:previous + exit 1 + fi + ''' + } + } + } + } + + post { + always { + cleanWs() + } + } +} diff --git a/Jenkinsfile.ci b/Jenkinsfile.ci new file mode 100644 index 0000000..1a51457 --- /dev/null +++ b/Jenkinsfile.ci @@ -0,0 +1,89 @@ +pipeline { + agent none + + options { + timestamps() + } + + environment { + NODE_OPTIONS = '--max_old_space_size=2048' + } + + stages { + + stage('Init') { + agent any + steps { + script { + env.COMMIT_AUTHOR = sh( + script: "git show -s --format=%an HEAD", + returnStdout: true + ).trim() + + env.COMMIT_SHORT = sh( + script: "git rev-parse --short HEAD", + returnStdout: true + ).trim() + } + + echo "CI build for commit ${env.COMMIT_SHORT} by ${env.COMMIT_AUTHOR}" + } + } + + /* ========================= + BACKEND CI + ========================= */ + + stage('Backend: lint & test') { + agent { + docker { + image 'python:3.11-slim' + args '-u root' + } + } + steps { + dir('backend') { + sh ''' + set -e + python -m venv .venv + . .venv/bin/activate + pip install --upgrade pip + pip install -r requirements-dev.txt + ruff check app tests + pytest + ''' + } + } + } + + /* ========================= + FRONTEND CI + ========================= */ + + stage('Frontend: check & build') { + agent { + docker { + image 'node:20-slim' + } + } + steps { + dir('frontend') { + sh ''' + set -e + npm install --no-progress --no-audit --prefer-offline + npm run check + npm run build + ''' + } + } + } + + + } + + post { + always { + cleanWs() + } + } +}