Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor: Jenkins Config YAML 기반 알림 플랫폼 유동적 지원 추가 완료 #632

Merged
merged 7 commits into from
Dec 20, 2024
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
Loading