Skip to content
This repository was archived by the owner on Aug 6, 2025. It is now read-only.

Commit 3df315c

Browse files
mmeigsbranberry
andauthored
DOP-3604: Github comment on Job Deploy (#842)
* clean slate * npm i and ci * bigger ephemeral - handleJobs * bigger ephemeral - all stg lambdas * expanding brain * esbuild * individual: true * move aws-sdk to devdeps * add serverless plugins * install oops * Use esbuild for lambdas * legacy-peer-deps, our old friend * more peers * upgrade memory-server to get rid of @types/mongodb * deploy lambdas, peer-deps * log * correct token * pass bot creds through env vars * fix links * look for builder-bot comments, fix links * log payload * remove mmeigs * remove org * cleaned, tested * remove gh-comment as github workflow trigger * PR feedback, clean, resolve dependencies * remove legacy-peer-deps * add branch to staging ecs workflow * updated deps * remove branch from staging ecs trigger * clean up * removed config input * remove config mentions --------- Co-authored-by: branberry <[email protected]>
1 parent 34953ea commit 3df315c

File tree

10 files changed

+29069
-4485
lines changed

10 files changed

+29069
-4485
lines changed

api/config/custom-environment-variables.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"dbUrl": "MONGO_ATLAS_URL",
1010
"fastlyDochubMap": "FASTLY_DOCHUB_MAP",
1111
"githubSecret": "GITHUB_SECRET",
12+
"githubBotPW": "GITHUB_BOT_PASSWORD",
1213
"slackSecret": "SLACK_SECRET",
1314
"slackAuthToken": "SLACK_TOKEN",
1415
"slackViewOpenUrl": "https://slack.com/api/views.open",

api/config/default.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
"dbUrl": "url",
1010
"fastlyDochubMap": "FASTLY_DOCHUB_MAP",
1111
"githubSecret": "GITHUB_SECRET",
12+
"githubBotPW": "GITHUB_BOT_PASSWORD",
1213
"slackSecret": "SLACK_SECRET",
1314
"slackAuthToken": "SLACK_TOKEN",
1415
"slackViewOpenUrl": "https://slack.com/api/views.open",

api/config/plugins.js

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
// source: https://github.com/evanw/esbuild/issues/1051
2+
const plugin = {
3+
name: 'fix',
4+
setup(build) {
5+
// If a ".node" file is imported within a module in the "file" namespace, resolve
6+
// it to an absolute path and put it into the "node-file" virtual namespace.
7+
build.onResolve({ filter: /\.node$/, namespace: 'file' }, (args) => ({
8+
path: require.resolve(args.path, { paths: [args.resolveDir] }),
9+
namespace: 'node-file',
10+
}));
11+
12+
// Files in the "node-file" virtual namespace call "require()" on the
13+
// path from esbuild of the ".node" file in the output directory.
14+
build.onLoad({ filter: /.*/, namespace: 'node-file' }, (args) => ({
15+
contents: `
16+
import path from ${JSON.stringify(args.path)}
17+
try { module.exports = require(path) }
18+
catch {}
19+
`,
20+
}));
21+
22+
// If a ".node" file is imported within a module in the "node-file" namespace, put
23+
// it in the "file" namespace where esbuild's default loading behavior will handle
24+
// it. It is already an absolute path since we resolved it to one above.
25+
build.onResolve({ filter: /\.node$/, namespace: 'node-file' }, (args) => ({
26+
path: args.path,
27+
namespace: 'file',
28+
}));
29+
30+
// Tell esbuild's default loading behavior to use the "file" loader for
31+
// these ".node" files.
32+
let opts = build.initialOptions;
33+
opts.loader = opts.loader || {};
34+
opts.loader['.node'] = 'file';
35+
},
36+
};
37+
38+
module.exports = [plugin];

api/controllers/v1/jobs.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { IConfig } from 'config';
44
import { RepoEntitlementsRepository } from '../../../src/repositories/repoEntitlementsRepository';
55
import { BranchRepository } from '../../../src/repositories/branchRepository';
66
import { ConsoleLogger } from '../../../src/services/logger';
7+
import { GithubCommenter } from '../../../src/services/github';
78
import { SlackConnector } from '../../../src/services/slack';
89
import { JobRepository } from '../../../src/repositories/jobRepository';
910
import { JobQueueMessage } from '../../../src/entities/queueMessage';
@@ -165,13 +166,40 @@ async function NotifyBuildSummary(jobId: string): Promise<any> {
165166
await client.connect();
166167
const db = client.db(c.get('dbName'));
167168
const env = c.get<string>('env');
169+
const githubToken = c.get<string>('githubBotPW');
168170

169171
const jobRepository = new JobRepository(db, c, consoleLogger);
170172
// TODO: Make fullDocument be of type Job, validate existence
171173
const fullDocument = await jobRepository.getJobById(jobId);
174+
if (!fullDocument) {
175+
consoleLogger.error(jobId, 'Cannot find job entry in db');
176+
return;
177+
}
172178
const repoName = fullDocument.payload.repoName;
173179
const username = fullDocument.user;
180+
const githubCommenter = new GithubCommenter(consoleLogger, githubToken);
174181
const slackConnector = new SlackConnector(consoleLogger, c);
182+
183+
// Create/Update Github comment
184+
try {
185+
const parentPRs = await githubCommenter.getParentPRs(fullDocument.payload);
186+
for (const pr of parentPRs) {
187+
const prCommentId = await githubCommenter.getPullRequestCommentId(fullDocument.payload, pr);
188+
const fullJobDashboardUrl = c.get<string>('dashboardUrl') + jobId;
189+
190+
if (prCommentId !== undefined) {
191+
const ghMessage = prepGithubComment(fullDocument, fullJobDashboardUrl, true);
192+
githubCommenter.updateComment(fullDocument.payload, prCommentId, ghMessage);
193+
} else {
194+
const ghMessage = prepGithubComment(fullDocument, fullJobDashboardUrl, false);
195+
githubCommenter.postComment(fullDocument.payload, pr, ghMessage);
196+
}
197+
}
198+
} catch (err) {
199+
consoleLogger.error(jobId, `Failed to comment on GitHub: ${err}`);
200+
}
201+
202+
// Slack notification
175203
const repoEntitlementRepository = new RepoEntitlementsRepository(db, c, consoleLogger);
176204
const entitlement = await repoEntitlementRepository.getSlackUserIdByGithubUsername(username);
177205
if (!entitlement?.['slack_user_id']) {
@@ -201,6 +229,18 @@ export const extractUrlFromMessage = (fullDocument): string[] => {
201229
return urls.map((url) => url.replace(/([^:]\/)\/+/g, '$1'));
202230
};
203231

232+
function prepGithubComment(fullDocument: Job, jobUrl: string, isUpdate = false): string {
233+
if (isUpdate) {
234+
return `\n* job log: [${fullDocument.payload.newHead}](${jobUrl})`;
235+
}
236+
const urls = extractUrlFromMessage(fullDocument);
237+
let stagingUrl = '';
238+
if (urls.length > 0) {
239+
stagingUrl = urls[urls.length - 1];
240+
}
241+
return `✨ Staging URL: [${stagingUrl}](${stagingUrl})\n\n#### 🪵 Logs\n\n* job log: [${fullDocument.payload.newHead}](${jobUrl})`;
242+
}
243+
204244
async function prepSummaryMessage(
205245
env: string,
206246
fullDocument: Job,

0 commit comments

Comments
 (0)