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

Verify that build status reporters indeed work #19

Merged
merged 16 commits into from
Oct 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1,018 changes: 464 additions & 554 deletions functions/package-lock.json

Large diffs are not rendered by default.

10 changes: 5 additions & 5 deletions functions/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,11 @@
},
"main": "lib/index.js",
"dependencies": {
"@octokit/auth-app": "^2.6.0",
"@octokit/auth-app": "^2.7.0",
"@octokit/rest": "^18.0.6",
"eris": "^0.13.3",
"firebase-admin": "^8.10.0",
"firebase-functions": "^3.6.1",
"firebase-admin": "^9.2.0",
"firebase-functions": "^3.11.0",
"httpie": "^1.1.2",
"jsdom": "^16.4.0",
"lodash": "^4.17.20",
Expand All @@ -29,12 +29,12 @@
},
"devDependencies": {
"@types/jsdom": "^16.2.4",
"@types/node": "^14.11.5",
"@types/node": "^14.11.10",
"@types/node-fetch": "^2.5.7",
"@types/semver": "^7.3.4",
"@typescript-eslint/eslint-plugin": "^3.9.1",
"@typescript-eslint/parser": "^3.8.0",
"eslint": "^7.6.0",
"eslint": "^7.11.0",
"eslint-plugin-import": "^2.22.0",
"firebase-functions-test": "^0.2.0",
"typescript": "^3.8.0"
Expand Down
12 changes: 10 additions & 2 deletions functions/src/api/reportBuildFailure.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ export const reportBuildFailure = functions.https.onRequest(async (req: Request,
}

const { body } = req;
firebase.logger.debug('Build failure report incoming.', body);

const { jobId, buildId, reason } = body;
const failure: BuildFailure = { reason };

Expand All @@ -26,10 +28,16 @@ export const reportBuildFailure = functions.https.onRequest(async (req: Request,
} catch (err) {
const message = `
Something went wrong while wrong while reporting a build failure
${err.message} (${err.status})\n${err.stackTrace}
${err.message}
`;
firebase.logger.error(message);
firebase.logger.error(message, err);
await Discord.sendAlert(message);

if (req.body?.jobId?.toString().startsWith('dryRun')) {
await CiBuilds.removeDryRunBuild(req.body.buildId);
await CiJobs.removeDryRunJob(req.body.jobId);
}

res.status(500).send('Something went wrong');
}
});
23 changes: 16 additions & 7 deletions functions/src/api/reportNewBuild.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ export const reportNewBuild = functions.https.onRequest(async (req: Request, res
}

const { body } = req;
firebase.logger.debug('new incoming build report', body);

const { buildId, jobId, imageType, baseOs, repoVersion, editorVersion, targetPlatform } = body;
const buildInfo: BuildInfo = {
baseOs,
Expand All @@ -25,8 +27,8 @@ export const reportNewBuild = functions.https.onRequest(async (req: Request, res
targetPlatform,
};

if (jobId === 'dryRun') {
await createDryRunJob(imageType, editorVersion);
if (jobId.toString().startsWith('dryRun')) {
await createDryRunJob(jobId, imageType, editorVersion);
}

await CiJobs.markJobAsInProgress(jobId);
Expand All @@ -37,21 +39,28 @@ export const reportNewBuild = functions.https.onRequest(async (req: Request, res
} catch (err) {
const message = `
Something went wrong while wrong while reporting a new build.
${err.message} (${err.status})\n${err.stackTrace}
${err.message}
`;
firebase.logger.error(message);
firebase.logger.error(message, err);
await Discord.sendAlert(message);

if (req.body?.jobId?.toString().startsWith('dryRun')) {
await CiBuilds.removeDryRunBuild(req.body.buildId);
await CiJobs.removeDryRunJob(req.body.jobId);
}

res.status(500).send('Something went wrong');
}
});

const createDryRunJob = async (imageType: ImageType, editorVersion: string) => {
const createDryRunJob = async (jobId: string, imageType: ImageType, editorVersion: string) => {
firebase.logger.debug('running dryrun for image', imageType, editorVersion);
const repoVersionInfo = await RepoVersionInfo.getLatest();

if (imageType === 'editor') {
const editorVersionInfo = await EditorVersionInfo.get(editorVersion);
await CiJobs.create(imageType, repoVersionInfo, editorVersionInfo);
await CiJobs.create(jobId, imageType, repoVersionInfo, editorVersionInfo);
} else {
await CiJobs.create(imageType, repoVersionInfo);
await CiJobs.create(jobId, imageType, repoVersionInfo);
}
};
30 changes: 22 additions & 8 deletions functions/src/api/reportPublication.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { firebase, functions } from '../config/firebase';
import { Request } from 'firebase-functions/lib/providers/https';
import { Response } from 'express-serve-static-core';
import { Token } from '../config/token';
import { CiBuilds, DockerInfo } from '../model/ciBuilds';
import { CiBuilds } from '../model/ciBuilds';
import { CiJobs } from '../model/ciJobs';
import { Discord } from '../config/discord';

Expand All @@ -15,28 +15,42 @@ export const reportPublication = functions.https.onRequest(async (req: Request,
}

const { body } = req;
const { jobId, buildId, imageRepo, imageName, friendlyTag, specificTag, digest } = body;
const dockerInfo: DockerInfo = { imageRepo, imageName, friendlyTag, specificTag, digest };
firebase.logger.debug('Publication report incoming.', body);
const isDryRun = req.body.jobId?.toString().startsWith('dryRun');

const { jobId, buildId, dockerInfo } = body;
await CiBuilds.markBuildAsPublished(buildId, dockerInfo);
const jobHasCompleted = await CiBuilds.haveAllBuildsForJobBeenPublished(jobId);
firebase.logger.info('Publication reported.', body);

if (jobHasCompleted) {
await CiJobs.markJobAsCompleted(jobId);
const message = `Job completed for ${jobId}.`;
const message = `New images published for ${jobId}.`;
firebase.logger.info(message);
await Discord.sendMessageToMaintainers(message);
if (!isDryRun) {
await Discord.sendMessageToMaintainers(message);
}
}

firebase.logger.info('Publication reported.', body);
if (isDryRun) {
await CiBuilds.removeDryRunBuild(req.body.buildId);
await CiJobs.removeDryRunJob(req.body.jobId);
}

res.status(200).send('OK');
} catch (err) {
const message = `
Something went wrong while wrong while reporting a new publication
${err.message} (${err.status})\n${err.stackTrace}
${err.message}
`;
firebase.logger.error(message);
firebase.logger.error(message, err);
await Discord.sendAlert(message);

if (req.body?.jobId?.toString().startsWith('dryRun')) {
await CiBuilds.removeDryRunBuild(req.body.buildId);
await CiJobs.removeDryRunJob(req.body.jobId);
}

res.status(500).send('Something went wrong');
}
});
2 changes: 0 additions & 2 deletions functions/src/logic/ingestRepoVersions/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import { updateDatabase } from './updateDatabase';
export const ingestRepoVersions = async () => {
try {
const scrapedInfoList = await scrapeVersions();
firebase.logger.info('Found versions', scrapedInfoList);

await updateDatabase(scrapedInfoList);
} catch (err) {
const message = `
Expand Down
2 changes: 1 addition & 1 deletion functions/src/logic/ingestUnityVersions/updateDatabase.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ export const updateDatabase = async (ingestedInfoList: EditorVersionInfo[]): Pro
firebase.logger.info(message);
await Discord.sendMessageToMaintainers(message);
} else {
firebase.logger.info('Database is up-to-date. (no updated info found)');
firebase.logger.info('Database is up-to-date. (no updated Unity versions found)');
}
};
62 changes: 39 additions & 23 deletions functions/src/model/ciBuilds.ts
Original file line number Diff line number Diff line change
Expand Up @@ -73,31 +73,48 @@ export class CiBuilds {
imageType: ImageType,
buildInfo: BuildInfo,
) => {
try {
const data: CiBuild = {
status: BuildStatus.started,
buildId,
relatedJobId,
imageType,
buildInfo,
failure: null,
dockerInfo: null,
meta: {
lastBuildStart: Timestamp.now(),
failureCount: 0,
lastBuildFailure: null,
publishedDate: null,
},
addedDate: Timestamp.now(),
modifiedDate: Timestamp.now(),
};

await db.collection(COLLECTION).doc(buildId).set({ data });
} catch (err) {
firebase.logger.error('Error occurred while trying to enqueue a new build', err);
const data: CiBuild = {
status: BuildStatus.started,
buildId,
relatedJobId,
imageType,
buildInfo,
failure: null,
dockerInfo: null,
meta: {
lastBuildStart: Timestamp.now(),
failureCount: 0,
lastBuildFailure: null,
publishedDate: null,
},
addedDate: Timestamp.now(),
modifiedDate: Timestamp.now(),
};

const ref = await db.collection(COLLECTION).doc(buildId);
const snapshot = await ref.get();

if (snapshot.exists) {
// noinspection ExceptionCaughtLocallyJS
throw new Error('A build with this identifier already exists');
}

const result = await ref.create(data);
firebase.logger.debug('Build created', result);
};

static async removeDryRunBuild(buildId: string) {
if (!buildId.startsWith('dryRun')) {
throw new Error('Unexpected behaviour, expected only dryRun builds to be deleted');
}

const ref = await db.collection(COLLECTION).doc(buildId);
const doc = await ref.get();
firebase.logger.info('dryRun produced this build endResult', doc.data());

await ref.delete();
}

static markBuildAsFailed = async (buildId: string, failure: BuildFailure) => {
const build = await db.collection(COLLECTION).doc(buildId);

Expand Down Expand Up @@ -125,7 +142,6 @@ export class CiBuilds {
const snapshot = await db
.collection(COLLECTION)
.where('jobId', '==', jobId)
// @ts-ignore
.where('status', '!=', BuildStatus.published)
.limit(1)
.get();
Expand Down
59 changes: 36 additions & 23 deletions functions/src/model/ciJobs.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { db, admin } from '../config/firebase';
import { db, admin, firebase } from '../config/firebase';
import { EditorVersionInfo } from './editorVersionInfo';
import FieldValue = admin.firestore.FieldValue;
import Timestamp = admin.firestore.Timestamp;
Expand Down Expand Up @@ -42,42 +42,47 @@ export class CiJobs {
};

static create = async (
jobId: string,
imageType: ImageType,
repoVersionInfo: RepoVersionInfo,
editorVersionInfo: EditorVersionInfo | null = null,
) => {
const jobId = await CiJobs.generateJobId(imageType, repoVersionInfo, editorVersionInfo);
await db
.collection(COLLECTION)
.doc(jobId)
.set({
status: JobStatus.created,
imageType,
repoVersionInfo,
editorVersionInfo,
meta: {
lastBuildStart: null,
failureCount: 0,
lastBuildFailure: null,
},
addedDate: Timestamp.now(),
modifiedDate: Timestamp.now(),
});
const job: CiJob = {
status: JobStatus.created,
imageType,
repoVersionInfo,
editorVersionInfo,
meta: {
lastBuildStart: null,
failureCount: 0,
lastBuildFailure: null,
},
addedDate: Timestamp.now(),
modifiedDate: Timestamp.now(),
};

const result = await db.collection(COLLECTION).doc(jobId).create(job);
firebase.logger.debug('Job created', result);
};

static markJobAsInProgress = async (jobId: string) => {
const job = await db.collection(COLLECTION).doc(jobId);
const snapshot = await job.get();
const ref = await db.collection(COLLECTION).doc(jobId);
const snapshot = await ref.get();

if (!snapshot.exists) {
throw new Error(`Trying to mark job '${jobId}' as in progress. But it does not exist.`);
}

const currentBuild = snapshot.data() as CiJob;
firebase.logger.warn(currentBuild);

// TODO - move this logic out of the model
// Do not override failure or completed
let { status } = currentBuild;
if ([JobStatus.created, JobStatus.scheduled].includes(status)) {
status = JobStatus.inProgress;
}

await job.update({
await ref.update({
status,
'meta.lastBuildStart': Timestamp.now(),
modifiedDate: Timestamp.now(),
Expand All @@ -89,7 +94,7 @@ export class CiJobs {

await job.update({
status: JobStatus.failure,
'meta.failures': FieldValue.increment(1),
'meta.failureCount': FieldValue.increment(1),
'meta.lastBuildFailure': Timestamp.now(),
modifiedDate: Timestamp.now(),
});
Expand All @@ -104,6 +109,14 @@ export class CiJobs {
});
};

static async removeDryRunJob(jobId: string) {
if (!jobId.startsWith('dryRun')) {
throw new Error('Expect only dryRun jobs to be deleted.');
}

await db.collection(COLLECTION).doc(jobId).delete();
}

static generateJobId(
imageType: string,
repoVersionInfo: RepoVersionInfo,
Expand Down
2 changes: 1 addition & 1 deletion functions/src/model/repoVersionInfo.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ export class RepoVersionInfo {
.limit(1)
.get();

if (snapshot.docs.length <= 1) {
if (snapshot.docs.length <= 0) {
throw new Error('No repository versions have been ingested yet');
}

Expand Down