Skip to content

Commit 3fc68e7

Browse files
authored
Merge pull request #159 from devtron-labs/develop
fix: Develop
2 parents 0121106 + 2cf04e9 commit 3fc68e7

7 files changed

Lines changed: 448 additions & 78 deletions

File tree

Dockerfile

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
FROM node AS builder
1+
FROM node:24 AS builder
22

33
WORKDIR /app
44
COPY package.json .
@@ -11,9 +11,12 @@ FROM node:24.11.0
1111

1212
RUN groupadd -r devtron && useradd -r -g devtron devtron
1313

14-
ENV TINI_VERSION v0.18.0
15-
RUN arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) && echo $arch && wget https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${arch} -O /tini
16-
RUN chmod +x /tini
14+
ENV TINI_VERSION=v0.18.0
15+
RUN apt-get update && apt-get install -y wget && \
16+
arch=$(arch | sed s/aarch64/arm64/ | sed s/x86_64/amd64/) && echo $arch && \
17+
wget https://github.com/krallin/tini/releases/download/${TINI_VERSION}/tini-${arch} -O /tini && \
18+
chmod +x /tini && \
19+
apt-get purge -y wget && apt-get autoremove -y && rm -rf /var/lib/apt/lists/*
1720
ENTRYPOINT ["/tini", "--"]
1821

1922
WORKDIR /app

package-lock.json

Lines changed: 11 additions & 14 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
"version": "1.0.0",
44
"description": "app for notification",
55
"main": "dist/server.js",
6+
"engines": {
7+
"node": ">=20.0.0"
8+
},
69
"scripts": {
710
"start": "ts-node src/server.ts",
811
"dev": "nodemon src/server.ts",
@@ -29,7 +32,7 @@
2932
"dependencies": {
3033
"@types/express": "^4.17.21",
3134
"@types/mustache": "^0.8.32",
32-
"@types/node": "^12.0.2",
35+
"@types/node": "^20.0.0",
3336
"@types/request": "^2.48.1",
3437
"axios": "^1.7.7",
3538
"body-parser": "^1.20.3",

src/common/mustacheHelper.ts

Lines changed: 59 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,65 @@ export class MustacheHelper {
7777
if(event.eventTypeId===EVENT_TYPE.ScoopNotification){
7878
return this.parseScoopNotification(event)
7979
}
80+
81+
const date = moment(event.eventTime);
82+
const timestamp = isSlackNotification
83+
? date.unix()
84+
: date.format('dddd, MMMM Do YYYY hh:mm A [GMT]Z');
85+
8086
let baseURL = event.baseUrl;
87+
88+
// Handle approval events FIRST (before checking pipelineType)
89+
if (event.eventTypeId===EVENT_TYPE.Approval){
90+
let imageTagNames,imageComment,imageLink,approvalLink;
91+
let index = -1;
92+
if (event.payload.dockerImageUrl) index = event.payload.dockerImageUrl.lastIndexOf(":");
93+
if (event.payload.imageTagNames) imageTagNames = event.payload.imageTagNames;
94+
if (event.payload.imageComment) imageComment = event.payload.imageComment;
95+
if (baseURL && event.payload.imageApprovalLink) imageLink =`${baseURL}${event.payload.imageApprovalLink}`;
96+
if (baseURL && event.payload.approvalLink) approvalLink = `${baseURL}${event.payload.approvalLink}`;
97+
98+
return {
99+
eventTime: timestamp,
100+
triggeredBy: event.payload.triggeredBy || "NA",
101+
appName: event.payload.appName || "NA",
102+
envName: event.payload.envName || "NA",
103+
pipelineName: event.payload.pipelineName || "NA",
104+
imageTag: index >= 0 ? event.payload.dockerImageUrl.substring(index + 1) : "NA",
105+
comment:imageComment,
106+
tags:imageTagNames,
107+
imageApprovalLink:imageLink,
108+
approvalLink:approvalLink,
109+
}
110+
}
111+
112+
if (event.eventTypeId===EVENT_TYPE.ConfigApproval){
113+
let protectConfigFileType,protectConfigFileName,protectConfigComment,protectConfigLink,envName,approvalLink;
114+
if (event.payload.protectConfigFileType) protectConfigFileType = event.payload.protectConfigFileType;
115+
if (event.payload.protectConfigFileName) protectConfigFileName = event.payload.protectConfigFileName;
116+
if (event.payload.protectConfigComment) protectConfigComment = event.payload.protectConfigComment.split("\n");
117+
if (baseURL && event.payload.protectConfigLink) protectConfigLink =`${baseURL}${event.payload.protectConfigLink}`;
118+
if (baseURL && event.payload.approvalLink) approvalLink = `${baseURL}${event.payload.approvalLink}`;
119+
if (!event.payload.envName){
120+
envName="Base configuration"
121+
}
122+
else{
123+
envName=event.payload.envName
124+
}
125+
return {
126+
eventTime: timestamp,
127+
triggeredBy: event.payload.triggeredBy || "NA",
128+
appName: event.payload.appName || "NA",
129+
envName: envName,
130+
protectConfigFileType:protectConfigFileType,
131+
protectConfigFileName:protectConfigFileName,
132+
protectConfigComment:protectConfigComment,
133+
protectConfigLink:protectConfigLink,
134+
approvalLink:approvalLink,
135+
}
136+
}
137+
138+
// Now handle CI/CD events (which need material parsing)
81139
let material = event.payload.material;
82140
let ciMaterials;
83141
if (event.eventTypeId!==EVENT_TYPE.Approval && event.eventTypeId!==EVENT_TYPE.ConfigApproval && event.eventTypeId!=EVENT_TYPE.ImagePromotion){
@@ -116,12 +174,6 @@ export class MustacheHelper {
116174
}) : [];
117175
}
118176

119-
120-
const date = moment(event.eventTime);
121-
const timestamp = isSlackNotification
122-
? date.unix()
123-
: date.format('dddd, MMMM Do YYYY hh:mm A [GMT]Z');
124-
125177
if (event.pipelineType === "CI") {
126178
let buildHistoryLink;
127179
if (baseURL && event.payload.buildHistoryLink) buildHistoryLink = `${baseURL}${event.payload.buildHistoryLink}`;
@@ -163,52 +215,7 @@ export class MustacheHelper {
163215
triggeredWithoutApprovalStyle: event.isDeploymentDoneWithoutApproval ? 'block' : 'none'
164216
}
165217
}
166-
else if (event.eventTypeId===EVENT_TYPE.Approval){
167-
let imageTagNames,imageComment,imageLink,approvalLink;
168-
let index = -1;
169-
if (event.payload.dockerImageUrl) index = event.payload.dockerImageUrl.lastIndexOf(":");
170-
if (event.payload.imageTagNames) imageTagNames = event.payload.imageTagNames;
171-
if (event.payload.imageComment) imageComment = event.payload.imageComment;
172-
if (baseURL && event.payload.imageApprovalLink) imageLink =`${baseURL}${event.payload.imageApprovalLink}`;
173-
if (baseURL && event.payload.approvalLink) approvalLink = `${baseURL}${event.payload.approvalLink}`;
174-
175-
return {
176-
eventTime: timestamp,
177-
triggeredBy: event.payload.triggeredBy || "NA",
178-
appName: event.payload.appName || "NA",
179-
envName: event.payload.envName || "NA",
180-
pipelineName: event.payload.pipelineName || "NA",
181-
imageTag: index >= 0 ? event.payload.dockerImageUrl.substring(index + 1) : "NA",
182-
comment:imageComment,
183-
tags:imageTagNames,
184-
imageApprovalLink:imageLink,
185-
approvalLink:approvalLink,
186-
}
187-
188-
189-
}
190-
else if (event.eventTypeId===EVENT_TYPE.ConfigApproval){
191-
let protectConfigFileType,protectConfigFileName,protectConfigComment,protectConfigLink,envName,approvalLink;
192-
if (event.payload.protectConfigFileType) protectConfigFileType = event.payload.protectConfigFileType;
193-
if (event.payload.protectConfigFileName) protectConfigFileName = event.payload.protectConfigFileName;
194-
if (event.payload.protectConfigComment) protectConfigComment = event.payload.protectConfigComment.split("\n");
195-
if (baseURL && event.payload.protectConfigLink) protectConfigLink =`${baseURL}${event.payload.protectConfigLink}`;
196-
if (baseURL && event.payload.approvalLink) approvalLink = `${baseURL}${event.payload.approvalLink}`;
197-
if (!event.payload.envName){
198-
envName="Base configuration"
199-
}
200-
return {
201-
eventTime: timestamp,
202-
triggeredBy: event.payload.triggeredBy || "NA",
203-
appName: event.payload.appName || "NA",
204-
envName: event.payload.envName || envName,
205-
protectConfigFileType:protectConfigFileType || "NA",
206-
protectConfigFileName:protectConfigFileName || "NA",
207-
protectConfigComment:protectConfigComment || [],
208-
protectConfigLink:protectConfigLink,
209-
approvalLink:approvalLink,
210-
}
211-
}
218+
// Note: Approval and ConfigApproval events are now handled at the top of this function
212219
else if (event.eventTypeId === EVENT_TYPE.ImagePromotion ){
213220

214221
let artifactPromotionRequestViewLink : string = `${baseURL}${event.payload?.artifactPromotionRequestViewLink}`

src/destination/destinationHandlers/slackHandler.ts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -150,7 +150,6 @@ export class SlackService implements Handler {
150150
let parsedEvent = this.mh.parseEvent(event as Event, true);
151151
jsons = Mustache.render(template, parsedEvent);
152152
}
153-
154153
let j = JSON.parse(jsons)
155154
const res = await sdk.send(
156155
{

src/notification/service/notificationService.ts

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,15 @@ class NotificationService {
7676
settings.pipeline_id = event.pipelineId
7777
settings.event_type_id = event.eventTypeId
7878
for (let h of this.handlers) {
79+
// Handle email notifications (SES and SMTP)
7980
if ((h instanceof SESService) || (h instanceof SMTPService)) {
8081
await h.handle(event, templateResults, settings, configsMap, destinationMap)
8182
}
83+
// Handle Slack notifications for approval events
84+
if (h instanceof SlackService) {
85+
this.logger.info("Processing Slack approval notification");
86+
await h.handle(event, templateResults, settings, configsMap, destinationMap)
87+
}
8288
}}
8389
catch(err) {
8490
this.logger.error("err" + err)
@@ -145,12 +151,19 @@ class NotificationService {
145151
this.logger.info(`Processing notification V2 for event type: ${event.eventTypeId}, correlationId: ${event.correlationId}`);
146152
this.logger.info(`Using ${notificationSettings.length} pre-provided notification settings`);
147153

148-
// Handle approval notifications
149-
if (event.payload.providers && event.payload.providers.length > 0) {
150-
this.logger.info(`Processing approval notification with ${event.payload.providers.length} providers`);
151-
await this.sendApprovalNotification(event);
152-
this.logger.info(`Approval notification sent successfully`);
153-
return new CustomResponse("notification sent", 200);
154+
// Handle approval notifications (eventTypeId 4 = Approval, 5 = ConfigApproval)
155+
// Approval events use event.payload.providers instead of notificationSettings
156+
if (event.eventTypeId === EVENT_TYPE.Approval || event.eventTypeId === EVENT_TYPE.ConfigApproval) {
157+
this.logger.info(`Detected approval event type: ${event.eventTypeId}`);
158+
if (event.payload.providers && event.payload.providers.length > 0) {
159+
this.logger.info(`Processing approval notification with ${event.payload.providers.length} providers`);
160+
await this.sendApprovalNotification(event);
161+
this.logger.info(`Approval notification sent successfully`);
162+
return new CustomResponse("notification sent", 200);
163+
} else {
164+
this.logger.warn(`Approval event received but no providers found in payload for event ${event.correlationId}`);
165+
return new CustomResponse("", 0, new CustomError("no providers found in payload for approval event", 400));
166+
}
154167
}
155168

156169
// Handle scoop notification events

0 commit comments

Comments
 (0)