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

Commit c2640e4

Browse files
authored
DOP-3951: Call Gatsby Cloud webhook after persistence module (#889)
1 parent 93645ef commit c2640e4

File tree

11 files changed

+155
-61
lines changed

11 files changed

+155
-61
lines changed

api/handlers/jobs.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,7 @@ export async function notifyBuildSummary(jobId: string, options: BuildSummaryOpt
107107
}
108108
const repoName = fullDocument.payload.repoName;
109109
const username = fullDocument.user;
110+
110111
const githubCommenter = new GithubCommenter(consoleLogger, githubToken);
111112
const slackConnector = new SlackConnector(consoleLogger, c);
112113

@@ -239,6 +240,7 @@ export async function snootyBuildComplete(event: APIGatewayEvent): Promise<APIGa
239240
await client.connect();
240241
const db = client.db(c.get<string>('dbName'));
241242
const jobRepository = new JobRepository(db, c, consoleLogger);
243+
await jobRepository.updateExecutionTime(jobId, { gatsbyCloudEndTime: new Date() });
242244
const updateResponse = await jobRepository.updateWithStatus(jobId, null, payload.status || JobStatus.failed, false);
243245
const previewUrl = getPreviewUrl(updateResponse.payload, c.get<string>('env'));
244246
await notifyBuildSummary(jobId, { mongoClient: client, previewUrl });
@@ -270,5 +272,5 @@ function getPreviewUrl(payload: Payload | undefined, env: string): string | unde
270272
const { repoOwner, branchName, project } = payload;
271273
const githubUsernameNoHyphens = repoOwner.split('-').join('').toLowerCase();
272274
const possibleStagingSuffix = env === 'stg' ? 'stg' : '';
273-
return `https://preview-mongodb${githubUsernameNoHyphens}${possibleStagingSuffix}.gatsbyjs.io/${project}/${branchName}/index`;
275+
return `https://preview-mongodb${githubUsernameNoHyphens}${possibleStagingSuffix}.gatsbyjs.io/${project}/${branchName}/`;
274276
}

src/job/jobHandler.ts

Lines changed: 58 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,20 @@ export abstract class JobHandler {
9999
null,
100100
null
101101
);
102-
await this.jobRepository.updateWithStatus(this.currJob._id, files, JobStatus.completed);
102+
103+
// Prevent the Autobuilder's usual build completion from being sent after content staging job
104+
// if the user already has a Gatsby Cloud site. Job should be marked as
105+
// completed after the Gatsby Cloud build via the SnootyBuildComplete lambda.
106+
const { _id: jobId, user } = this.currJob;
107+
const gatsbyCloudSiteId = await this._repoEntitlementsRepo.getGatsbySiteIdByGithubUsername(user);
108+
if (gatsbyCloudSiteId && this.currJob.payload.jobType === 'githubPush') {
109+
this.logger.info(
110+
jobId,
111+
`User ${user} has a Gatsby Cloud site. The Autobuilder will not mark the build as completed right now.`
112+
);
113+
} else {
114+
await this.jobRepository.updateWithStatus(jobId, files, JobStatus.completed);
115+
}
103116
} else {
104117
if (publishResult.error) {
105118
await this.jobRepository.updateWithErrorStatus(this.currJob._id, publishResult.error);
@@ -266,14 +279,15 @@ export abstract class JobHandler {
266279
[`${stage}EndTime`]: end,
267280
};
268281

269-
this._jobRepository.findOneAndUpdateExecutionTime(this.currJob._id, update);
282+
this._jobRepository.updateExecutionTime(this.currJob._id, update);
270283
return resp;
271284
}
272285

273286
private async exeBuildModified(): Promise<void> {
274287
const stages = {
275288
['get-build-dependencies']: 'buildDepsExe',
276289
['next-gen-parse']: 'parseExe',
290+
['persistence-module']: 'persistenceExe',
277291
['next-gen-html']: 'htmlExe',
278292
['oas-page-build']: 'oasPageBuildExe',
279293
};
@@ -303,6 +317,12 @@ export abstract class JobHandler {
303317
const makeCommandsResp = await this._commandExecutor.execute([command]);
304318
await this.logBuildDetails(makeCommandsResp);
305319
}
320+
321+
// Call Gatsby Cloud preview webhook after persistence module finishes for staging builds
322+
const isFeaturePreviewWebhookEnabled = process.env.GATSBY_CLOUD_PREVIEW_WEBHOOK_ENABLED?.toLowerCase() === 'true';
323+
if (key === 'persistence-module' && this.name === 'Staging' && isFeaturePreviewWebhookEnabled) {
324+
await this.callGatsbyCloudWebhook();
325+
}
306326
}
307327
await this._logger.save(this.currJob._id, `${'(BUILD)'.padEnd(15)}Finished Build`);
308328
}
@@ -635,27 +655,44 @@ export abstract class JobHandler {
635655
return this._logger;
636656
}
637657

638-
protected async previewWebhook(): Promise<AxiosResponse<string>> {
639-
const previewWebhookURL = 'https://webhook.gatsbyjs.com/hooks/data_source';
640-
const githubUsername = this.currJob.user;
641-
const gatsbySiteId = await this._repoEntitlementsRepo.getGatsbySiteIdByGithubUsername(githubUsername);
642-
if (!gatsbySiteId) {
643-
const message = `User ${githubUsername} does not have a Gatsby Cloud Site ID.`;
644-
this._logger.warn('Gatsby Cloud Preview Webhook', message);
645-
throw new Error(message);
646-
}
658+
// Invokes Gatsby Cloud Preview Webhook
659+
protected async callGatsbyCloudWebhook(): Promise<void> {
660+
const featurePreviewWebhookEnabled = process.env.GATSBY_CLOUD_PREVIEW_WEBHOOK_ENABLED;
661+
// Logging for Debugging purposes only will remove once we see the build working in Gatsby.
662+
await this.logger.save(
663+
this.currJob._id,
664+
`${'(GATSBY_CLOUD_PREVIEW_WEBHOOK_ENABLED)'.padEnd(15)}${featurePreviewWebhookEnabled}`
665+
);
647666

648-
const url = `${previewWebhookURL}/${gatsbySiteId}`;
649-
return await axios.post(
650-
url,
651-
{
652-
jobId: this.currJob._id,
653-
status: this.currJob.status,
654-
},
655-
{
656-
headers: { 'x-gatsby-cloud-data-source': 'gatsby-source-snooty-preview' },
667+
try {
668+
const previewWebhookURL = 'https://webhook.gatsbyjs.com/hooks/data_source';
669+
const githubUsername = this.currJob.user;
670+
const gatsbySiteId = await this._repoEntitlementsRepo.getGatsbySiteIdByGithubUsername(githubUsername);
671+
if (!gatsbySiteId) {
672+
const message = `User ${githubUsername} does not have a Gatsby Cloud Site ID.`;
673+
this._logger.warn('Gatsby Cloud Preview Webhook', message);
674+
throw new Error(message);
657675
}
658-
);
676+
677+
const url = `${previewWebhookURL}/${gatsbySiteId}`;
678+
const response = await axios.post(
679+
url,
680+
{
681+
jobId: this.currJob._id,
682+
},
683+
{
684+
headers: { 'x-gatsby-cloud-data-source': 'gatsby-source-snooty-preview' },
685+
}
686+
);
687+
await this._jobRepository.updateExecutionTime(this.currJob._id, { gatsbyCloudStartTime: new Date() });
688+
await this.logger.save(this.currJob._id, `${'(POST Webhook Status)'.padEnd(15)}${response.status}`);
689+
} catch (err) {
690+
await this.logger.save(
691+
this.currJob._id,
692+
`${'(POST Webhook)'.padEnd(15)}Failed to POST to Gatsby Cloud webhook: ${err}`
693+
);
694+
throw err;
695+
}
659696
}
660697
}
661698

src/job/productionJobHandler.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ export class ProductionJobHandler extends JobHandler {
134134
if (this.currJob?.buildCommands) {
135135
this.currJob.buildCommands[this.currJob.buildCommands.length - 1] = 'make get-build-dependencies';
136136
this.currJob.buildCommands.push('make next-gen-parse');
137+
this.currJob.buildCommands.push('make persistence-module');
137138
this.currJob.buildCommands.push('make next-gen-html');
138139
this.currJob.buildCommands.push(`make oas-page-build MUT_PREFIX=${this.currJob.payload.mutPrefix}`);
139140
}

src/job/stagingJobHandler.ts

Lines changed: 2 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,8 @@ export class StagingJobHandler extends JobHandler {
5858
prepStageSpecificNextGenCommands(): void {
5959
if (this.currJob.buildCommands) {
6060
this.currJob.buildCommands[this.currJob.buildCommands.length - 1] = 'make next-gen-parse';
61-
this.currJob.buildCommands.push(`make next-gen-html GH_USER=${this.currJob.payload.repoOwner}`);
61+
this.currJob.buildCommands.push(`make persistence-module GH_USER=${this.currJob.payload.repoOwner}`);
62+
this.currJob.buildCommands.push('make next-gen-html');
6263
const project = this.currJob.payload.project === 'cloud-docs' ? this.currJob.payload.project : '';
6364
const branchName = /^[a-zA-Z0-9_\-\./]+$/.test(this.currJob.payload.branchName)
6465
? this.currJob.payload.branchName
@@ -75,25 +76,6 @@ export class StagingJobHandler extends JobHandler {
7576
if (resp?.output?.includes('Summary')) {
7677
resp.output = resp.output.slice(resp.output.indexOf('Summary'));
7778
}
78-
// Invoke Gatsby Preview Webhook
79-
const featurePreviewWebhookEnabled = process.env.GATSBY_CLOUD_PREVIEW_WEBHOOK_ENABLED;
80-
// Logging for Debugging purposes only will remove once we see the build working in Gatsby.
81-
await this.logger.save(
82-
this.currJob._id,
83-
`${'(GATSBY_CLOUD_PREVIEW_WEBHOOK_ENABLED)'.padEnd(15)}${featurePreviewWebhookEnabled}`
84-
);
85-
if (featurePreviewWebhookEnabled?.toLowerCase() === 'true') {
86-
try {
87-
const response = await this.previewWebhook();
88-
await this.logger.save(this.currJob._id, `${'(POST Webhook Status)'.padEnd(15)}${response.status}`);
89-
} catch (err) {
90-
await this.logger.save(
91-
this.currJob._id,
92-
`${'(POST Webhook)'.padEnd(15)}Failed to POST to Gatsby Cloud webhook: ${err}`
93-
);
94-
}
95-
}
96-
9779
await this.logger.save(this.currJob._id, `${'(stage)'.padEnd(15)}Finished pushing to staging`);
9880
await this.logger.save(this.currJob._id, `${'(stage)'.padEnd(15)}Staging push details:\n\n${summary}`);
9981
return resp;

src/repositories/jobRepository.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -101,17 +101,14 @@ export class JobRepository extends BaseRepository {
101101
await this._queueConnector.sendMessage(new JobQueueMessage(jobId, status, 0, taskId), url, delay);
102102
}
103103

104-
async findOneAndUpdateExecutionTime(id: string, setValues: { [key: string]: number }): Promise<void> {
104+
async updateExecutionTime(id: string, setValues: { [key: string]: number | Date }): Promise<void> {
105105
const query = {
106106
_id: new objectId(id),
107107
};
108108
const update = { $set: setValues };
109-
const options = { sort: { priority: -1, createdTime: 1 }, returnNewDocument: true };
110-
this.findOneAndUpdate(query, update, options, `Mongo Timeout Error: Timed out while retrieving job`).catch(
111-
(err) => {
112-
this._logger.error('findOneAndUpdateExecutionTime', `Error at findOneAndUpdate: ${err}`);
113-
}
114-
);
109+
this.updateOne(query, update, `Mongo Timeout Error: Timed out while retrieving job`).catch((err) => {
110+
this._logger.error('updateExecutionTime', `Error: ${err}`);
111+
});
115112
}
116113

117114
async findOneAndUpdateJob(query): Promise<Job | null> {

src/repositories/repoEntitlementsRepository.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ export class RepoEntitlementsRepository extends BaseRepository {
4747
}
4848
}
4949

50-
async getGatsbySiteIdByGithubUsername(githubUsername: string) {
50+
async getGatsbySiteIdByGithubUsername(githubUsername: string): Promise<string | undefined> {
5151
const query = { github_username: githubUsername };
5252
const projection = { _id: 0, gatsby_site_id: 1 };
5353
const res = await this.findOne(
@@ -57,7 +57,7 @@ export class RepoEntitlementsRepository extends BaseRepository {
5757
);
5858
if (!res) {
5959
this._logger.error('Fetching Gatsby Cloud Site ID', `Could not find user: ${githubUsername}`);
60-
return null;
60+
return undefined;
6161
}
6262
return res.gatsby_site_id;
6363
}

tests/data/data.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,7 @@ export class TestDataProvider {
145145
return Array<string>().concat(genericCommands.slice(0, genericCommands.length - 1), [
146146
'make get-build-dependencies',
147147
'make next-gen-parse',
148+
'make persistence-module',
148149
'make next-gen-html',
149150
`make oas-page-build MUT_PREFIX=${job.payload.mutPrefix}`,
150151
]);
@@ -162,7 +163,8 @@ export class TestDataProvider {
162163
const genericCommands = TestDataProvider.getCommonBuildCommands(job);
163164
const commands = Array<string>().concat(genericCommands.slice(0, genericCommands.length - 1), [
164165
'make next-gen-parse',
165-
`make next-gen-html GH_USER=${job.payload.repoOwner}`,
166+
`make persistence-module GH_USER=${job.payload.repoOwner}`,
167+
`make next-gen-html`,
166168
]);
167169
const project = job.payload.project === 'cloud-docs' ? job.payload.project : '';
168170
const branchName = /^[a-zA-Z0-9_\-\./]+$/.test(job.payload.branchName) ? job.payload.branchName : '';

tests/data/jobDef.ts

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,47 @@ export const getBuildJobPlain = (): Job => ({
5151
} as Payload,
5252
});
5353

54+
export const getStagingJobDef = (): Job => ({
55+
_id: '5c5e0817ce099eaf874a9801',
56+
title: 'GitHub Push: skerschb',
57+
buildCommands: [],
58+
comMessage: null,
59+
createdTime: new Date('2022-04-20T17:10:09.432Z'),
60+
deployCommands: [],
61+
62+
endTime: new Date('2022-04-20T17:10:09.432Z'),
63+
error: {},
64+
invalidationStatusURL: 'test-status-url',
65+
logs: [],
66+
manifestPrefix: '',
67+
mutPrefix: '',
68+
pathPrefix: '',
69+
priority: 1,
70+
purgedUrls: null,
71+
result: [],
72+
shouldGenerateSearchManifest: true,
73+
startTime: new Date('2022-04-20T17:10:09.432Z'),
74+
status: JobStatus.completed,
75+
user: 'skerschb',
76+
payload: {
77+
jobType: 'githubPush',
78+
action: 'push',
79+
branchName: 'DOCSP-666',
80+
isFork: false,
81+
manifestPrefix: undefined,
82+
mutPrefix: undefined,
83+
newHead: '38b805e9c7c4f1c364476682e93f9d24a87f470a',
84+
pathPrefix: undefined,
85+
prefix: 'compass',
86+
project: 'testauth',
87+
repoName: 'testauth',
88+
repoOwner: 'skerschb',
89+
source: 'github',
90+
url: 'https://github.com/skerschb/testauth.git',
91+
urlSlug: 'UsingAlias',
92+
} as Payload,
93+
});
94+
5495
// Represents a manifestJob at time of insert to queue
5596
export const getManifestJobDef = (): Omit<Job, '_id'> => ({
5697
buildCommands: [],

tests/unit/job/api/jobs.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ jest.mock('config', () => ({
1515

1616
jest.mock('../../../../src/repositories/jobRepository', () => ({
1717
JobRepository: jest.fn().mockImplementation(() => ({
18+
updateExecutionTime: jest.fn(),
1819
updateWithStatus: jest.fn(() => mockJob),
1920
getJobById: jest.fn(),
2021
})),

tests/unit/job/stagingJobHandler.test.ts

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { TestDataProvider } from '../../data/data';
22
import { JobHandlerTestHelper } from '../../utils/jobHandlerTestHelper';
3-
import { getBuildJobDef } from '../../data/jobDef';
3+
import { getStagingJobDef } from '../../data/jobDef';
44

55
describe('StagingJobHandler Tests', () => {
66
let jobHandlerTestHelper: JobHandlerTestHelper;
@@ -71,6 +71,7 @@ describe('StagingJobHandler Tests', () => {
7171
expect(jobHandlerTestHelper.job.buildCommands).toEqual(
7272
TestDataProvider.getExpectedStagingBuildNextGenCommands(jobHandlerTestHelper.job)
7373
);
74+
expect(jobHandlerTestHelper.jobRepo.updateWithStatus).toBeCalledTimes(1);
7475
expect(jobHandlerTestHelper.jobRepo.insertNotificationMessages).toBeCalledWith(
7576
jobHandlerTestHelper.job._id,
7677
'Summary: All good'
@@ -90,12 +91,18 @@ describe('StagingJobHandler Tests', () => {
9091
jobHandlerTestHelper.jobRepo.insertJob = jest.fn();
9192
const queueManifestJobSpy = jest.spyOn(jobHandlerTestHelper.jobHandler, 'queueManifestJob');
9293

93-
expect(jobHandlerTestHelper.job).toEqual(getBuildJobDef());
94+
expect(jobHandlerTestHelper.job).toEqual(getStagingJobDef());
9495

9596
jobHandlerTestHelper.setupForSuccess();
9697
await jobHandlerTestHelper.jobHandler.execute();
9798

9899
expect(queueManifestJobSpy).toBeCalledTimes(0);
99100
expect(jobHandlerTestHelper.jobRepo.insertJob).toBeCalledTimes(0);
100101
});
102+
103+
test('Staging deploy with Gatsby Cloud site does not result in job completion', async () => {
104+
jobHandlerTestHelper.setStageForDeploySuccess(true, false, undefined, { hasGatsbySiteId: true });
105+
await jobHandlerTestHelper.jobHandler.execute();
106+
expect(jobHandlerTestHelper.jobRepo.updateWithStatus).toBeCalledTimes(0);
107+
});
101108
});

0 commit comments

Comments
 (0)