Skip to content
This repository was archived by the owner on Feb 2, 2021. It is now read-only.

Commit 27f57cc

Browse files
rosen-vladimirovDimitar Kerezov
authored and
Dimitar Kerezov
committed
Allow hooks to provide implementation for decorated methods
Whenever a before-hook returns a function it will be used instead of the original method. When executing such a substitute function it receives a pointer to the original one as well as all its arguments.
1 parent 6da5007 commit 27f57cc

File tree

2 files changed

+35
-9
lines changed

2 files changed

+35
-9
lines changed

helpers.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -281,14 +281,32 @@ export function appendZeroesToVersion(version: string, requiredVersionLength: nu
281281
return version;
282282
}
283283

284-
export function decorateMethod(before: (method1: any, self1: any, args1: any[]) => Promise<void>, after: (method2: any, self2: any, result2: any, args2: any[]) => Promise<any>) {
284+
export function decorateMethod(before: (method1: any, self1: any, args1: any[]) => Promise<any>, after: (method2: any, self2: any, result2: any, args2: any[]) => Promise<any>) {
285285
return (target: Object, propertyKey: string, descriptor: TypedPropertyDescriptor<Function>) => {
286286
const sink = descriptor.value;
287287
descriptor.value = async function (...args: any[]): Promise<any> {
288+
let newMethods: Function[] = null;
288289
if (before) {
289-
await before(sink, this, args);
290+
newMethods = await before(sink, this, args);
290291
}
291-
const result = sink.apply(this, args);
292+
293+
let hasBeenReplaced = false;
294+
let result: any;
295+
if (newMethods && newMethods.length) {
296+
// Find all functions
297+
_(newMethods)
298+
.filter(f => _.isFunction(f))
299+
.each(f => {
300+
// maybe add logger.trace here
301+
hasBeenReplaced = true;
302+
result = f(args, sink.bind(this));
303+
});
304+
}
305+
306+
if (!hasBeenReplaced) {
307+
result = sink.apply(this, args);
308+
}
309+
292310
if (after) {
293311
return await after(sink, this, result, args);
294312
}
@@ -327,7 +345,7 @@ export function hook(commandName: string) {
327345
return decorateMethod(
328346
async (method: any, self: any, args: any[]) => {
329347
const hooksService = getHooksService(self);
330-
await hooksService.executeBeforeHooks(commandName, prepareArguments(method, args, hooksService));
348+
return hooksService.executeBeforeHooks(commandName, prepareArguments(method, args, hooksService));
331349
},
332350
async (method: any, self: any, resultPromise: any, args: any[]) => {
333351
const result = await resultPromise;

services/hooks-service.ts

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export class HooksService implements IHooksService {
6363
return this.executeHooks(afterHookName, traceMessage, hookArguments);
6464
}
6565

66-
private async executeHooks(hookName: string, traceMessage: string, hookArguments?: IDictionary<any>): Promise<void> {
66+
private async executeHooks(hookName: string, traceMessage: string, hookArguments?: IDictionary<any>): Promise<any> {
6767
if (this.$config.DISABLE_HOOKS || !this.$options.hooks) {
6868
return;
6969
}
@@ -75,19 +75,22 @@ export class HooksService implements IHooksService {
7575
this.initialize(projectDir);
7676

7777
this.$logger.trace(traceMessage);
78-
78+
const results: any[] = [];
7979
try {
8080
for (const hooksDirectory of this.hooksDirectories) {
81-
await this.executeHooksInDirectory(hooksDirectory, hookName, hookArguments);
81+
results.push(await this.executeHooksInDirectory(hooksDirectory, hookName, hookArguments));
8282
}
8383
} catch (err) {
8484
this.$logger.trace("Failed during hook execution.");
8585
this.$errors.failWithoutHelp(err.message || err);
8686
}
87+
88+
return _.flatten(results);
8789
}
8890

89-
private async executeHooksInDirectory(directoryPath: string, hookName: string, hookArguments?: IDictionary<any>): Promise<void> {
91+
private async executeHooksInDirectory(directoryPath: string, hookName: string, hookArguments?: IDictionary<any>): Promise<any[]> {
9092
hookArguments = hookArguments || {};
93+
const results: any[] = [];
9194
const hooks = this.getHooksByName(directoryPath, hookName);
9295
for (let i = 0; i < hooks.length; ++i) {
9396
const hook = hooks[i];
@@ -129,7 +132,8 @@ export class HooksService implements IHooksService {
129132
if (maybePromise) {
130133
this.$logger.trace('Hook promises to signal completion');
131134
try {
132-
await maybePromise;
135+
const result = await maybePromise;
136+
results.push(result);
133137
} catch (err) {
134138
if (err && _.isBoolean(err.stopExecution) && err.errorAsWarning === true) {
135139
this.$logger.warn(err.message || err);
@@ -144,12 +148,16 @@ export class HooksService implements IHooksService {
144148
this.$logger.trace("Executing %s hook at location %s with environment ", hookName, hook.fullPath, environment);
145149

146150
const output = await this.$childProcess.spawnFromEvent(command, [hook.fullPath], "close", environment, { throwError: false });
151+
results.push(output);
152+
147153
if (output.exitCode !== 0) {
148154
throw new Error(output.stdout + output.stderr);
149155
}
150156
}
151157
}
152158
}
159+
160+
return results;
153161
}
154162

155163
private getHooksByName(directoryPath: string, hookName: string): IHook[] {

0 commit comments

Comments
 (0)