Skip to content

Commit

Permalink
refactor: Jenkins Config YAML 기반 알림 플랫폼 유동적 지원 추가 완료 (#637)
Browse files Browse the repository at this point in the history
Co-authored-by: 한관희 <[email protected]>
  • Loading branch information
mingmingmon and limehee authored Dec 20, 2024
1 parent 41f71c8 commit ba19038
Show file tree
Hide file tree
Showing 4 changed files with 207 additions and 101 deletions.
68 changes: 53 additions & 15 deletions jenkins/prod/Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -140,31 +140,52 @@ pipeline {
}

post {
failure {
success {
script {
sendSlackBuildNotification(":scream_cat: Stage *${FAILED_STAGE}* failed.", env.SLACK_COLOR_FAILURE)
sendBuildNotification(":rocket: Deployment completed successfully", env.NOTIFICATION_COLOR_SUCCESS)
}
}

success {
failure {
script {
sendSlackBuildNotification(":rocket: Deployment completed successfully", env.SLACK_COLOR_SUCCESS)
sendBuildNotification(":scream_cat: Deployment failed in stage *${FAILED_STAGE}*", env.NOTIFICATION_COLOR_FAILURE)
}
}
}
}

def sendSlackBuildNotification(String message, String color) {
def sendBuildNotification(String message, String color) {
def jobUrl = "${env.JENKINS_DOMAIN}/job/${env.JOB_NAME}"
def consoleOutputUrl = "${jobUrl}/${env.BUILD_NUMBER}/console"
def changelog = env.GIT_CHANGELOG

def notificationPlatforms = readJSON text: env.NOTIFICATION_PLATFORMS_JSON.trim()

notificationPlatforms.each { notification ->
if (notification.enabled.toBoolean()) {
def platform = notification.platform ? notification.platform.trim().toLowerCase() : ""
echo "Processing notification for platform: '${platform}'"

def payload = null
switch (platform) {
case 'slack':
payload = createSlackPayload(message, color, jobUrl, consoleOutputUrl, changelog)
break
case 'discord':
payload = createDiscordPayload(message, color, jobUrl, consoleOutputUrl, changelog)
break
default:
echo "Unsupported or undefined notification platform: '${platform}'"
}

def payload = createSlackPayload(message, color, jobUrl, consoleOutputUrl)
def payloadJson = groovy.json.JsonOutput.toJson(payload)

sendHttpPostRequest(env.SLACK_WEBHOOK_URL, payloadJson)
if (payload != null) {
def payloadJson = groovy.json.JsonOutput.toJson(payload)
sendHttpPostRequest(notification.'webhook-url', payloadJson)
}
}
}
}

def createSlackPayload(String message, String color, String jobUrl, String consoleOutputUrl) {
def createSlackPayload(String message, String color, String jobUrl, String consoleOutputUrl, String changelog) {
return [
blocks: [
[
Expand All @@ -183,7 +204,7 @@ def createSlackPayload(String message, String color, String jobUrl, String conso
type: "section",
text: [
type: "mrkdwn",
text: "*Change Log:*\n${env.GIT_CHANGELOG}"
text: "*Change Log:*\n${changelog}"
]
],
[
Expand Down Expand Up @@ -217,6 +238,23 @@ def createSlackPayload(String message, String color, String jobUrl, String conso
]
}

def createDiscordPayload(String message, String color, String jobUrl, String consoleOutputUrl, String changelog) {
return [
embeds: [
[
title: message,
color: parseColor(color),
description: "*Change Log:*\n${changelog}\n\n[Job](${jobUrl}) | [Console Output](${consoleOutputUrl})",
]
]
]
}

def parseColor(String hexColor) {
// Discord requires the color in decimal format
return Integer.parseInt(hexColor.replace("#", ""), 16)
}

def sendHttpPostRequest(String url, String payload) {
def CONTENT_TYPE_JSON = 'application/json'
def HTTP_POST = 'POST'
Expand All @@ -233,9 +271,9 @@ def loadEnvironmentVariables(String configFile) {
def config = readYaml(file: configFile)

env.JENKINS_DOMAIN = config.'jenkins-domain'
env.SLACK_WEBHOOK_URL = config.slack.'webhook-url'
env.SLACK_COLOR_SUCCESS = config.slack.'color-success'
env.SLACK_COLOR_FAILURE = config.slack.'color-failure'
env.NOTIFICATION_COLOR_SUCCESS = config.notifications.common.'color-success'
env.NOTIFICATION_COLOR_FAILURE = config.notifications.common.'color-failure'
env.NOTIFICATION_PLATFORMS_JSON = groovy.json.JsonOutput.toJson(config.notifications.platforms)

env.PG_USER = config.postgresql.user
env.PG_PASSWORD = config.postgresql.password
Expand Down
92 changes: 53 additions & 39 deletions jenkins/prod/config.yml
Original file line number Diff line number Diff line change
@@ -1,60 +1,74 @@
jenkins-domain: "https://jenkins.example.com" # Jenkins domain
jenkins-domain: "https://jenkins.example.com" # Base URL of the Jenkins instance

slack:
webhook-url: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" # Slack webhook URL
color-success: "#F2C744" # Slack message color for success
color-failure: "#8D1E0E" # Slack message color for failure
notifications:
common:
color-success: "#F2C744" # Common hex color code for success messages across all notification platforms
color-failure: "#8D1E0E" # Common hex color code for failure messages across all notification platforms

platforms:
- platform: "slack" # Name of the notification platform (e.g., Slack)
enabled: true # Enable (true) or disable (false) notifications for this platform
webhook-url: "https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXXXXXXXXXXXXXX" # Webhook URL for sending messages to Slack

- platform: "discord" # Name of the notification platform (e.g., Discord)
enabled: true # Enable (true) or disable (false) notifications for this platform
webhook-url: "https://discord.com/api/webhooks/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" # Webhook URL for sending messages to Discord

# Add additional notification platforms below as needed
# Example:
# - platform: "microsoft-teams"
# enabled: true
# webhook-url: "https://outlook.office.com/webhook/..."

postgresql:
user: "postgres_user" # PostgreSQL username
password: "postgres_password" # PostgreSQL password
backup-dir: "/var/backups/postgresql" # Directory for PostgreSQL backups
user: "postgres_user" # Username for PostgreSQL
password: "postgres_password" # Password for PostgreSQL
backup-dir: "/var/backups/postgresql" # Directory where PostgreSQL backups are stored

dockerhub:
repo: "yourdockerhub/repository" # Docker Hub repository name
user: "dockerhub_user" # Docker Hub username
password: "dockerhub_password" # Docker Hub password
repo: "yourdockerhub/repository" # Docker Hub repository name
user: "dockerhub_user" # Docker Hub username
password: "dockerhub_password" # Docker Hub password

external-server:
config-path: "/path/to/external/config" # Path for external server configuration
cloud-path: "/path/to/external/cloud" # Path for external server cloud storage
logs-path: "/path/to/external/logs" # Path for external server logs
config-path: "/path/to/external/config" # Path to external server configuration files
cloud-path: "/path/to/external/cloud" # Path to external server cloud storage
logs-path: "/path/to/external/logs" # Path to external server log files

internal-server:
config-path: "/path/to/internal/config" # Path for internal server configuration
cloud-path: "/path/to/internal/cloud" # Path for internal server cloud storage
logs-path: "/path/to/internal/logs" # Path for internal server logs
config-path: "/path/to/internal/config" # Path to internal server configuration files
cloud-path: "/path/to/internal/cloud" # Path to internal server cloud storage
logs-path: "/path/to/internal/logs" # Path to internal server log files

containers:
blue: "blue-container" # Blue-Green deployment: Blue container name
green: "green-container" # Blue-Green deployment: Green container name
blue-url: "http://blue-container:8080" # URL for the Blue container environment
green-url: "http://green-container:8080" # URL for the Green container environment
image-name: "application-image" # Docker image name for the application
blue: "blue-container" # Name of the Blue container in Blue-Green deployment
green: "green-container" # Name of the Green container in Blue-Green deployment
blue-url: "http://blue-container:8080" # URL for accessing the Blue container environment
green-url: "http://green-container:8080" # URL for accessing the Green container environment
image-name: "application-image" # Docker image name for the application

networks:
application: "application-network" # Docker network for the application
monitoring: "monitoring-network" # Docker network for monitoring
application: "application-network" # Docker network used by the application
monitoring: "monitoring-network" # Docker network used for monitoring services

spring:
profile: "default" # Spring profile setting
port-a: 8080 # Application port A
port-b: 8081 # Application port B
profile: "default" # Spring profile setting
port-a: 8080 # Application port A
port-b: 8081 # Application port B

admin:
username: "admin" # Backend admin username
password: "admin_password" # Backend admin password
username: "admin" # Username for the backend admin
password: "admin_password" # Password for the backend admin

docker:
dockerfile-path: "/jenkins/prod/Dockerfile" # Path to the Dockerfile
nginx-container-name: "nginx" # Nginx container name
postgresql-container-name: "postgresql" # PostgreSQL container name
dockerfile-path: "/jenkins/prod/Dockerfile" # Path to the Dockerfile used for building the application image
nginx-container-name: "nginx" # Name of the Nginx container
postgresql-container-name: "postgresql" # Name of the PostgreSQL container

staging:
user: "user" # Staging user name
host: "host" # Staging host name or IP address
backup-dir-path: "/var/backups/postgresql" # Staging Directory Path for PostgreSQL backups
restore-backup-script-path: "/var/restore.sh" # Staging Restore Backup Script Path
ssh-port: 22 # Staging SSH Port
postgresql-user: "postgres_user" # Staging Postgresql User

user: "user" # Username for accessing the staging environment
host: "host" # Hostname or IP address of the staging server
backup-dir-path: "/var/backups/postgresql" # Directory path on the staging server for PostgreSQL backups
restore-backup-script-path: "/var/restore.sh" # Path to the script on the staging server for restoring backups
ssh-port: 22 # SSH port for accessing the staging server
postgresql-user: "postgres_user" # PostgreSQL username on the staging server
68 changes: 53 additions & 15 deletions jenkins/stage/Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -118,31 +118,52 @@ pipeline {
}

post {
failure {
success {
script {
sendSlackBuildNotification(":scream_cat: Stage *${FAILED_STAGE}* failed.", env.SLACK_COLOR_FAILURE)
sendBuildNotification(":rocket: Deployment completed successfully", env.NOTIFICATION_COLOR_SUCCESS)
}
}

success {
failure {
script {
sendSlackBuildNotification(":rocket: Deployment completed successfully", env.SLACK_COLOR_SUCCESS)
sendBuildNotification(":scream_cat: Deployment failed in stage *${FAILED_STAGE}*", env.NOTIFICATION_COLOR_FAILURE)
}
}
}
}

def sendSlackBuildNotification(String message, String color) {
def sendBuildNotification(String message, String color) {
def jobUrl = "${env.JENKINS_DOMAIN}/job/${env.JOB_NAME}"
def consoleOutputUrl = "${jobUrl}/${env.BUILD_NUMBER}/console"
def changelog = env.GIT_CHANGELOG

def notificationPlatforms = readJSON text: env.NOTIFICATION_PLATFORMS_JSON.trim()

notificationPlatforms.each { notification ->
if (notification.enabled.toBoolean()) {
def platform = notification.platform ? notification.platform.trim().toLowerCase() : ""
echo "Processing notification for platform: '${platform}'"

def payload = null
switch (platform) {
case 'slack':
payload = createSlackPayload(message, color, jobUrl, consoleOutputUrl, changelog)
break
case 'discord':
payload = createDiscordPayload(message, color, jobUrl, consoleOutputUrl, changelog)
break
default:
echo "Unsupported or undefined notification platform: '${platform}'"
}

def payload = createSlackPayload(message, color, jobUrl, consoleOutputUrl)
def payloadJson = groovy.json.JsonOutput.toJson(payload)

sendHttpPostRequest(env.SLACK_WEBHOOK_URL, payloadJson)
if (payload != null) {
def payloadJson = groovy.json.JsonOutput.toJson(payload)
sendHttpPostRequest(notification.'webhook-url', payloadJson)
}
}
}
}

def createSlackPayload(String message, String color, String jobUrl, String consoleOutputUrl) {
def createSlackPayload(String message, String color, String jobUrl, String consoleOutputUrl, String changelog) {
return [
blocks: [
[
Expand All @@ -161,7 +182,7 @@ def createSlackPayload(String message, String color, String jobUrl, String conso
type: "section",
text: [
type: "mrkdwn",
text: "*Change Log:*\n${env.GIT_CHANGELOG}"
text: "*Change Log:*\n${changelog}"
]
],
[
Expand Down Expand Up @@ -195,6 +216,23 @@ def createSlackPayload(String message, String color, String jobUrl, String conso
]
}

def createDiscordPayload(String message, String color, String jobUrl, String consoleOutputUrl, String changelog) {
return [
embeds: [
[
title: message,
color: parseColor(color),
description: "*Change Log:*\n${changelog}\n\n[Job](${jobUrl}) | [Console Output](${consoleOutputUrl})",
]
]
]
}

def parseColor(String hexColor) {
// Discord requires the color in decimal format
return Integer.parseInt(hexColor.replace("#", ""), 16)
}

def sendHttpPostRequest(String url, String payload) {
def CONTENT_TYPE_JSON = 'application/json'
def HTTP_POST = 'POST'
Expand All @@ -211,9 +249,9 @@ def loadEnvironmentVariables(String configFile) {
def config = readYaml(file: configFile)

env.JENKINS_DOMAIN = config.'jenkins-domain'
env.SLACK_WEBHOOK_URL = config.slack.'webhook-url'
env.SLACK_COLOR_SUCCESS = config.slack.'color-success'
env.SLACK_COLOR_FAILURE = config.slack.'color-failure'
env.NOTIFICATION_COLOR_SUCCESS = config.notifications.common.'color-success'
env.NOTIFICATION_COLOR_FAILURE = config.notifications.common.'color-failure'
env.NOTIFICATION_PLATFORMS_JSON = groovy.json.JsonOutput.toJson(config.notifications.platforms)

env.PG_USER = config.postgresql.user
env.PG_PASSWORD = config.postgresql.password
Expand Down
Loading

0 comments on commit ba19038

Please sign in to comment.