Skip to content

Commit

Permalink
chore(build-tools): add ts formatter and refactor build setup
Browse files Browse the repository at this point in the history
- add formatter for consistent ts code
- prevent tests from compiling into ./dist
  • Loading branch information
adamreese committed Dec 8, 2017
1 parent 833789a commit 7b69207
Show file tree
Hide file tree
Showing 12 changed files with 987 additions and 818 deletions.
13 changes: 9 additions & 4 deletions brigade-worker/package.json
Expand Up @@ -5,27 +5,32 @@
"main": "dist/index",
"types": "dist/index",
"scripts": {
"clean": "rimraf dist",
"format": "prettier --write \"src/**/*.ts\"",
"prestart": "node prestart.js",
"start": "node --no-deprecation ./dist/src/index.js",
"test": "tsc && mocha ./dist/test",
"start": "yarn build && node --no-deprecation ./dist/index.js",
"test": "mocha --compilers ts:ts-node/register --recursive \"test/**/*.ts\"",
"build": "tsc",
"brigade": "tsc && yarn start",
"brigade": "yarn start",
"docs": "typedoc --out ./doc --excludePrivate --excludeExternals --exclude test/*.ts --exclude doc/** ./src"
},
"author": "The Steel Thread Team",
"license": "MIT",
"repository": "https://github.com/Azure/brigade",
"devDependencies": {
"@kubernetes/typescript-node": "^0.1.1",
"@types/chai": "^4.0.1",
"@types/mocha": "^2.2.41",
"@types/node": "^8.0.14",
"chai": "^4.1.0",
"mocha": "^3.4.2",
"prettier": "^1.9.1",
"rimraf": "^2.6.2",
"ts-node": "^3.3.0",
"typedoc": "^0.8.0",
"typescript": "^2.4.2"
},
"dependencies": {
"@kubernetes/typescript-node": "^0.1.1",
"ulid": "^0.2.0"
}
}
2 changes: 1 addition & 1 deletion brigade-worker/prestart.js
Expand Up @@ -9,7 +9,7 @@ try {
let wrapper = "const {whitelistRequire} = require('./require');((require) => {" +
data.toString() +
"})(whitelistRequire)"
fs.writeFile("dist/src/brigade.js", wrapper, () => {
fs.writeFile("dist/brigade.js", wrapper, () => {
console.log("prestart: src/brigade.js written")
})
} catch(e) {
Expand Down
149 changes: 78 additions & 71 deletions brigade-worker/src/app.ts
@@ -1,23 +1,27 @@
/**
* Module app is the main application runner.
*/
import * as ulid from "ulid"
import * as ulid from "ulid";

import * as events from "./events"
import * as process from "process"
import * as k8s from "./k8s"
import * as brigadier from './brigadier'
import * as events from "./events";
import * as process from "process";
import * as k8s from "./k8s";
import * as brigadier from "./brigadier";

interface BuildStorage {
create(e:events.BrigadeEvent, project: events.Project, size?: string): Promise<string>
destroy(): Promise<boolean>
create(
e: events.BrigadeEvent,
project: events.Project,
size?: string
): Promise<string>;
destroy(): Promise<boolean>;
}

/**
* ProjectLoader describes a function able to load a Project.
*/
interface ProjectLoader {
(projectID: string, projectNS: string): Promise<events.Project>
(projectID: string, projectNS: string): Promise<events.Project>;
}

/**
Expand All @@ -35,101 +39,103 @@ export class App {
* In general, though, it should be left on. In some cases, by the time the
* process trap is invoked, the runtime is not in a good state to continue.
*/
public exitOnError: boolean = true
protected errorsHandled: boolean = false
protected lastEvent: events.BrigadeEvent
protected projectID: string
protected projectNS: string
public exitOnError: boolean = true;
protected errorsHandled: boolean = false;
protected lastEvent: events.BrigadeEvent;
protected projectID: string;
protected projectNS: string;
// On project loading error, this value may be passed. In all other cases,
// it is overwritten by an actual project.
protected proj: events.Project = new events.Project()
protected proj: events.Project = new events.Project();

// true if the "after" event has fired.
protected afterHasFired: boolean = false
protected storageIsDestroyed: boolean = false
protected afterHasFired: boolean = false;
protected storageIsDestroyed: boolean = false;
/**
* loadProject is a function that loads projects.
*/
public loadProject: ProjectLoader = k8s.loadProject
public loadProject: ProjectLoader = k8s.loadProject;
/**
* buildStorage controls the per-build storage layer.
*/
public buildStorage: BuildStorage = new k8s.BuildStorage()

public buildStorage: BuildStorage = new k8s.BuildStorage();

/**
* Create a new App.
*
* An app requires a project ID and project NS.
*/
constructor(projectID: string, projectNS: string) {
this.projectID = projectID
this.projectNS = projectNS
this.projectID = projectID;
this.projectNS = projectNS;
}
/**
* run runs a particular event for this app.
*/
public run(e: events.BrigadeEvent): Promise<boolean> {
this.lastEvent = e
this.lastEvent = e;

// This closure destroys storage for us. It is called by event handlers.
let destroyStorage = () => {
// Since we catch a destroy error, the outer wrapper will
// not get that error. Essentially, we swallow the error to prevent
// cleanup from exiting > 0.
return this.buildStorage.destroy().then( destroyed => {
if (!destroyed) {
console.log(`storage not destroyed for ${ e.workerID }`)
}
}).catch(reason => {
var msg = reason
// Kubernetes objects put error messages here:
if (reason.body && reason.body.message) {
msg = reason.body.message
}
console.log(`failed to destroy storage for ${ e.workerID }: ${ msg }`)
})
}
return this.buildStorage
.destroy()
.then(destroyed => {
if (!destroyed) {
console.log(`storage not destroyed for ${e.workerID}`);
}
})
.catch(reason => {
var msg = reason;
// Kubernetes objects put error messages here:
if (reason.body && reason.body.message) {
msg = reason.body.message;
}
console.log(`failed to destroy storage for ${e.workerID}: ${msg}`);
});
};

// We need at least one error trap to avoid losing the error to a new
// throw from EventEmitter.
brigadier.events.once("error", () => {
console.log("error handler is cleaning up")
this.exitOnError && process.exit(1)
})
console.log("error handler is cleaning up");
this.exitOnError && process.exit(1);
});

// We need to ensure that after is called exactly once. So we need an
// empty after handler.
brigadier.events.once("after", () => {
this.afterHasFired = true
this.afterHasFired = true;

// Delay long enough to cause beforeExit to be emitted again.
setImmediate(() => {
console.log("after: default event fired")
}, 20)
})
console.log("after: default event fired");
}, 20);
});

// Run if an uncaught rejection happens.
process.on("unhandledRejection", (reason: any, p: Promise<any>) => {
var msg = reason
var msg = reason;
// Kubernetes objects put error messages here:
if (reason.body && reason.body.message) {
msg = reason.body.message
msg = reason.body.message;
}
console.log(`FATAL: ${ msg } (rejection)`)
this.fireError(reason, "unhandledRejection")
})
console.log(`FATAL: ${msg} (rejection)`);
this.fireError(reason, "unhandledRejection");
});

// Run at the end.
process.on("beforeExit", (code) => {
process.on("beforeExit", code => {
if (this.afterHasFired) {
// So at this point, the after event has fired and we can cleanup.
if (!this.storageIsDestroyed) {
console.log("beforeExit(2): destroying storage")
this.storageIsDestroyed = true
destroyStorage()
console.log("beforeExit(2): destroying storage");
this.storageIsDestroyed = true;
destroyStorage();
}
return
return;
}

let after: events.BrigadeEvent = {
Expand All @@ -142,29 +148,31 @@ export class App {
event: e,
trigger: code == 0 ? "success" : "failure"
} as events.Cause
}
};

// Only fire an event if the top-level had a match.
if (brigadier.events.has(e.type)) {
brigadier.fire(after, this.proj)
brigadier.fire(after, this.proj);
} else {
this.afterHasFired = true
this.afterHasFired = true;
setImmediate(() => {
console.log("no-after: fired")
}, 20)
console.log("no-after: fired");
}, 20);
}
})
});

// Now that we have all the handlers registered, load the project and
// execute the event.
return this.loadProject(this.projectID, this.projectNS).then (p => {
this.proj = p
// Setup storage
return this.buildStorage.create(e, p, "50Mi")
}).then( () => {
brigadier.fire(e, this.proj)
return true
}) // We want to trigger the main rejection handler, so we do not catch().
return this.loadProject(this.projectID, this.projectNS)
.then(p => {
this.proj = p;
// Setup storage
return this.buildStorage.create(e, p, "50Mi");
})
.then(() => {
brigadier.fire(e, this.proj);
return true;
}); // We want to trigger the main rejection handler, so we do not catch().
}

/**
Expand All @@ -175,9 +183,9 @@ export class App {
*/
public fireError(reason?: any, errorType?: string): void {
if (this.errorsHandled) {
return
return;
}
this.errorsHandled = true
this.errorsHandled = true;

let errorEvent: events.BrigadeEvent = {
buildID: this.lastEvent.buildID,
Expand All @@ -190,9 +198,8 @@ export class App {
reason: reason,
trigger: errorType
} as events.Cause
}
};

brigadier.fire(errorEvent, this.proj)
brigadier.fire(errorEvent, this.proj);
}
}

37 changes: 18 additions & 19 deletions brigade-worker/src/brigadier.ts
Expand Up @@ -6,14 +6,14 @@

/** */

import * as jobImpl from "./job"
import * as groupImpl from "./group"
import * as eventsImpl from "./events"
import {JobRunner} from "./k8s"
import * as jobImpl from "./job";
import * as groupImpl from "./group";
import * as eventsImpl from "./events";
import { JobRunner } from "./k8s";

// These are filled by the 'fire' event handler.
let currentEvent = null
let currentProject = null
let currentEvent = null;
let currentProject = null;

/**
* events is the main event registry.
Expand All @@ -22,7 +22,7 @@ let currentProject = null
* where the `name` is the event name, and the callback is the function to be
* executed when the event is triggered.
*/
export let events = new eventsImpl.EventRegistry()
export let events = new eventsImpl.EventRegistry();

/**
* fire triggers an event.
Expand All @@ -32,9 +32,9 @@ export let events = new eventsImpl.EventRegistry()
* If no event handler is found, nothing happens.
*/
export function fire(e: eventsImpl.BrigadeEvent, p: eventsImpl.Project) {
currentEvent = e
currentProject = p
events.fire(e, p)
currentEvent = e;
currentProject = p;
events.fire(e, p);
}

/**
Expand All @@ -48,15 +48,15 @@ export function fire(e: eventsImpl.BrigadeEvent, p: eventsImpl.Project) {
* (in order) inside of the image. When no tasks are supplied, the image is
* executed as-is.
*/
export class Job extends jobImpl.Job{
export class Job extends jobImpl.Job {
run(): Promise<jobImpl.Result> {
let jr = new JobRunner(this, currentEvent, currentProject)
this._podName = jr.name
let jr = new JobRunner(this, currentEvent, currentProject);
this._podName = jr.name;
return jr.run().catch(err => {
// Wrap the message to give clear context.
let msg = `job ${ this.name }(${ jr.name }): ${ err }`
return Promise.reject(msg)
})
let msg = `job ${this.name}(${jr.name}): ${err}`;
return Promise.reject(msg);
});
}
}

Expand All @@ -78,12 +78,11 @@ export class ErrorReport {
/**
* cause is the BrigadeEvent that caused the error.
*/
public cause: eventsImpl.BrigadeEvent
public cause: eventsImpl.BrigadeEvent;
/**
* reason is the message that the error reporter received that describes the error.
*
* It may be empty if no error description was provided.
*/
public reason?: any

public reason?: any;
}

0 comments on commit 7b69207

Please sign in to comment.