pipeline { agent any parameters { string( name: 'REPO_URL', defaultValue: 'https://git.crowmate.fr/crowmate/Nest.git', description: 'Gitea repository URL (to retrieve docker-compose.prod.yml)' ) string( name: 'BRANCH', defaultValue: 'main', description: 'Branch' ) string( name: 'STACK_NAME', defaultValue: 'nest', description: 'Stack name in Portainer' ) string( name: 'IMAGE_TAG', defaultValue: 'latest', description: 'Image tag to deploy' ) } environment { GITEA_CREDENTIALS_ID = 'gitea-token' PORTAINER_URL = 'https://docker.devgoblin.fr' PORTAINER_ENV_ID = '3' } stages { stage('Clone') { steps { cleanWs() checkout([ $class: 'GitSCM', branches: [[name: "*/${params.BRANCH}"]], userRemoteConfigs: [[ url: params.REPO_URL, credentialsId: env.GITEA_CREDENTIALS_ID ]] ]) echo "Repository cloned" } } stage('Validation') { steps { script { if (!fileExists('docker-compose.prod.yml')) { error("docker-compose.prod.yml not found at the repository root") } echo "docker-compose.prod.yml found" } } } stage('Deploy to Portainer') { steps { withCredentials([string(credentialsId: 'portainer-token', variable: 'PORTAINER_TOKEN')]) { sh ''' COMPOSE_CONTENT=$(base64 -w 0 docker-compose.prod.yml) # Get the list of stacks STACKS=$(curl -s -X GET "''' + env.PORTAINER_URL + '''/api/stacks" \ -H "X-API-Key: $PORTAINER_TOKEN") # Check whether the stack already exists STACK_ID=$(echo "$STACKS" | jq -r '.[] | select(.Name == "''' + params.STACK_NAME + '''") | .Id') if [ -n "$STACK_ID" ]; then echo "Existing stack found (ID: $STACK_ID), updating..." RESPONSE=$(curl -s -X PUT "''' + env.PORTAINER_URL + '''/api/stacks/$STACK_ID?endpointId=''' + env.PORTAINER_ENV_ID + '''" \ -H "X-API-Key: $PORTAINER_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"stackFileContent\": \"$COMPOSE_CONTENT\", \"prune\": true, \"pullImage\": true}") else echo "Creating stack ''' + params.STACK_NAME + '''..." RESPONSE=$(curl -s -X POST "''' + env.PORTAINER_URL + '''/api/stacks/create/standalone/string?endpointId=''' + env.PORTAINER_ENV_ID + '''" \ -H "X-API-Key: $PORTAINER_TOKEN" \ -H "Content-Type: application/json" \ -d "{\"name\": \"''' + params.STACK_NAME + '''\", \"stackFileContent\": \"$COMPOSE_CONTENT\"}") fi # Check whether the response contains an error if echo "$RESPONSE" | jq -e '.message' > /dev/null 2>&1; then echo "Portainer error: $(echo $RESPONSE | jq -r '.message')" exit 1 fi echo "Stack deployed successfully" ''' } } } } post { success { echo "Stack '${params.STACK_NAME}' deployed to Portainer (tag: ${params.IMAGE_TAG})" } failure { echo "Failed to deploy stack '${params.STACK_NAME}'" } } }