Skip to content
Permalink
Browse files

Merge remote-tracking branch 'origin/develop' into feature/default-ts…

…-translations
  • Loading branch information...
baflo committed May 7, 2019
2 parents f9b397e + 38e8c91 commit 64d26047e145ef3cf5a037ff7aa79be480c0715b
@@ -48,6 +48,7 @@ version 0.4.0
- adds possibility to use platform sessions, for example session system of alexa or google assistant, and makes platform sessions the default session storage
- introduces @filter decorator, which works like a beforeIntentHook, but is made specifically for state redirections (which should be the most common use case for hooks)
- minor changes and improvements
- add CLI command 'assistant deploy'. Allows you to publish your voice application configuration to all registered platforms.

version 0.3.2
- fixes intent configuration in generator. Entities will be mapped with utterances only once. (@denselmann)
@@ -1,6 +1,15 @@
import { AssistantJSApplicationInitializer, AssistantJSSetup, FilterSetup, GeneratorApplication, ServerApplication, StateMachineSetup } from "assistant-source";
import {
AssistantJSApplicationInitializer,
AssistantJSSetup,
FilterSetup,
ServerApplication,
StateMachineSetup,
DeploymentApplication,
GeneratorApplication
} from "assistant-source";
import componentConfiguration from "./config/components";

import { MainApplication } from "inversify-components";
import * as path from "path"
/**
* This is AssistantJS's main entrance into your application. With the help of this ApplicationInitializer class, you help AssistantJS
* to initialize your application for starting the server, generating configuration files or running specs.
@@ -52,6 +61,8 @@ export class ApplicationInitializer implements AssistantJSApplicationInitializer

// Create and prepare setup instances
const setups = this.createAndPrepareSetups();

// Bind all AssistantJS root scope component
setups.assistantJs.autobind();

// Create ServerApplication instance - you might want to pass your own express instance here!
@@ -63,18 +74,41 @@ export class ApplicationInitializer implements AssistantJSApplicationInitializer
}

/** Called via cli command "assistant generate" */
public runGenerator() {
public async runGenerator(buildTimeStamp: number = Date.now()) {
return this.runApplication(GeneratorApplication, buildTimeStamp);
}

/** Called via cli command "assistant deploy" */
public async runProviderDeployment(buildTimeStamp: number = Date.now()) {
return this.runApplication(DeploymentApplication, buildTimeStamp);
}

/**
* Execute Application within the AssistantJS container scope
* @param ApplicationClass Class of @type {MainApplication}
* @param buildTimeStamp Path to the global build directory like '{rootDir}/builds'
* @returns A current AssistantJS instance
*/
public async runApplication(
ApplicationClass: (new (...args: any[]) => MainApplication),
buildTimeStamp: number
) {
ApplicationInitializer.printUnhandledRejections();

// Create and prepare setup instances
const setups = this.createAndPrepareSetups();

// Bind all AssistantJS root scope components
setups.assistantJs.autobind();

// Create ServerApplication instance - you might want to pass your own express instance here!
const serverApplication = new GeneratorApplication(`${process.cwd()}/builds`);
const serverApplication = new ApplicationClass(
path.join(process.cwd(), "builds"),
buildTimeStamp
);

// Let's get started!
setups.assistantJs.run(serverApplication);
await setups.assistantJs.run(serverApplication);
return setups.assistantJs;
}

@@ -0,0 +1,75 @@
import * as fs from "fs";
import * as path from "path";
import { CLIDeploymentExtension } from "../../../src/assistant-source";
import { DeploymentApplication } from "../../../src/components/root/app-deployment";
import { componentInterfaces } from "../../../src/components/root/private-interfaces";
import { ThisContext } from "../../this-context";

interface CurrentThisContext extends ThisContext {
/**
* Spy object for the CLIDeploymentExtension execute method. Injected by componentInterfaces.deployments
*/
deploymentSpy: jasmine.Spy;

/**
* Current instance of the DeploymentApplication
*/
deploymentApplication: DeploymentApplication;

/**
* A global mock timestamp
*/
buildTimeStamp: number;
}

const { existsSync } = fs;

describe("DeploymentApplication", function() {
beforeEach(async function(this: CurrentThisContext) {
this.deploymentSpy = jasmine.createSpy("execute");

this.inversify.bind<CLIDeploymentExtension>(componentInterfaces.deployments).toDynamicValue(() => {
return {
execute: this.deploymentSpy,
};
});
});

describe("with non existing buildDir", function() {
describe("execute", function() {
it("executes all bound platform deployments", async function(this: CurrentThisContext) {
try {
this.deploymentApplication = new DeploymentApplication("tmp");
fail("Should throw a missing build directory exception");
} catch (e) {
expect(e.message).toContain("Missing build directory");
}
});
});
});

describe("with existing buildDir", function() {
beforeEach(async function(this: CurrentThisContext) {
(fs as any).existsSync = jasmine.createSpy("existsSync").and.returnValue(true);
});

afterEach(function() {
(fs as any).existsSync = existsSync;
});
describe("execute", function() {
beforeEach(async function(this: CurrentThisContext) {
this.buildTimeStamp = Date.now();
this.deploymentApplication = new DeploymentApplication("root", this.buildTimeStamp);
this.deploymentApplication.execute(this.assistantJs.container);
});

it("executes all bound platform deployments", async function(this: CurrentThisContext) {
expect(this.deploymentSpy).toHaveBeenCalledTimes(1);
});

it("transmit the build directory", async function(this: CurrentThisContext) {
expect(this.deploymentSpy).toHaveBeenCalledWith(path.join("root", this.buildTimeStamp.toString()));
});
});
});
});
@@ -47,7 +47,7 @@ describe("GeneratorApplication", function() {
(fs as any).existsSync = this.spy.existsSync;

/** Create an instance of the GeneratorApplication */
this.generatorApplication = new GeneratorApplication(this.baseDir);
this.generatorApplication = new GeneratorApplication(this.baseDir, this.buildTimestamp.getTime());

/** Create a spy on the used CLIGeneratorExtension */
this.generatorExtension = this.assistantJs.container.inversifyInstance.getAll<CLIGeneratorExtension>(componentInterfaces.generator)[0];
@@ -84,7 +84,7 @@ describe("GeneratorApplication", function() {
});

it("creates the base directory", async function(this: CurrentThisContext) {
expect(this.spy.mkdirSync!).toHaveBeenCalledWith(this.baseDir);
expect(this.spy.mkdirSync!).toHaveBeenCalledWith(path.join(this.baseDir, this.buildTimestamp.getTime().toString()));
});
});

@@ -12,6 +12,7 @@ export * from "./components/joined-interfaces";
export { AssistantJSSetup } from "./setup";
export { ServerApplication } from "./components/root/app-server";
export { GeneratorApplication } from "./components/root/app-generator";
export { DeploymentApplication } from "./components/root/app-deployment";
export { GenericRequestHandler } from "./components/root/generic-request-handler";
export { defaultBunyan } from "./components/root/default-bunyan";
export { StateMachineSetup } from "./components/state-machine/state-intent-setup";
@@ -45,6 +45,10 @@ export function cli(argv, resolvedApplicationInitializer) {
fs.writeFileSync(destination, contents.replace(/\{\{__NAME__\}\}/g, name));
};

const deployConfiguration = async function(buildTimeStamp: number) {
return grabInitializer().runProviderDeployment(buildTimeStamp);
};

/** Initializes new assistantjs project (prototyped currently) */
const createProject = function(name: string) {
// Path to new project
@@ -202,6 +206,22 @@ export function cli(argv, resolvedApplicationInitializer) {
process.exit(0);
});

// Register new command
commander
.command("deploy")
.alias("d")
.description("Deploy current intent configuration to all provider")
.action(async () => {
// Create an timestamp witch will be
const timestamp = Date.now();
// Execute generator
await grabInitializer().runGenerator(timestamp);
console.log("Deploy configuration...");
// Execute deploy generated schemas
await deployConfiguration(timestamp);
process.exit(0);
});

// Register new command
commander
.command("list-extension-points")
@@ -3,3 +3,5 @@ export { descriptor as unifierDescriptor } from "./unifier/descriptor";
export { descriptor as stateMachineDescriptor } from "./state-machine/descriptor";
export { descriptor as serviceDescriptor } from "./services/descriptor";
export { descriptor as i18nDescriptor } from "./i18n/descriptor";

export { DeploymentApplication } from "./root/app-deployment";
@@ -30,10 +30,13 @@ export interface AssistantJSApplicationInitializer {
runServer(port?: number): AssistantJSSetup;

/** Called via cli command "assistant generate" */
runGenerator(): AssistantJSSetup;
runGenerator(buildTimeStamp?: number): Promise<AssistantJSSetup>;

/** Creates a ready-to-use AssistantJSSetup instance */
createAssistantJsSetup(): AssistantJSSetup;

/** Called via cli command "assistant deploy" */
runProviderDeployment(buildTimeStamp: number): Promise<AssistantJSSetup>;
}

/** Session keys used by AssistantJS for internal purposes */
@@ -0,0 +1,19 @@
import * as fs from "fs";
import { Container } from "inversify-components";
import { componentInterfaces } from "./private-interfaces";
import { CLIDeploymentExtension } from "./public-interfaces";

/**
* Application class which execute all platform specific deployments
*/
export class DeploymentApplication {
constructor(private buildDir: string, private buildTimeStamp: number = Date.now()) {
if (!fs.existsSync(buildDir)) throw new Error("Missing build directory. Previously you have to execute the generator.");
}

public async execute(container: Container): Promise<void> {
// Get all bound deployments and execute them
const deployments = container.inversifyInstance.getAll<CLIDeploymentExtension>(componentInterfaces.deployments);
await Promise.all(deployments.map(deployment => deployment.execute(`${this.buildDir}/${this.buildTimeStamp}`)));
}
}
@@ -6,33 +6,16 @@ import { CLIGeneratorExtension } from "./public-interfaces";

// This class is the main application thread. Therefore it acts like a singleton!
export class GeneratorApplication implements MainApplication {
private baseDir: string;
private buildNr!: number;
private buildDir!: string;
private container!: Container;

constructor(baseDir: string) {
this.baseDir = baseDir;
}
constructor(private baseDir: string, private buildTimeStamp: number) {}

public async execute(container: Container): Promise<void> {
this.container = container;
this.buildNr = Date.now();
this.buildDir = path.join(this.baseDir, `${this.buildNr}`);

/**
* Check if the base directory exists and recreate it if it's not found.
* Generally assistant new should create this directory.
*/
if (!fs.existsSync(this.baseDir)) {
fs.mkdirSync(this.baseDir);
}
const buildDir = path.join(this.baseDir, this.buildTimeStamp.toString());

// Create directory for current build
fs.mkdirSync(this.buildDir);
fs.mkdirSync(buildDir);

// Get and execute all builders
const builders = this.container.inversifyInstance.getAll<CLIGeneratorExtension>(componentInterfaces.generator);
await Promise.all(builders.map(builder => Promise.resolve(builder.execute(this.buildDir))));
const builders = container.inversifyInstance.getAll<CLIGeneratorExtension>(componentInterfaces.generator);
await Promise.all(builders.map(builder => Promise.resolve(builder.execute(buildDir))));
}
}
@@ -6,6 +6,7 @@ export const componentInterfaces = {
generator: Symbol("generator"),
loggerMiddleware: Symbol("logger-middleware"),
eventHandler: Symbol("event-handler"),
deployments: Symbol("deployments"),
};

export namespace Configuration {
@@ -49,7 +49,17 @@ export interface ContextDeriver {
/** Interface to fulfill to register a generator (called via cli: "assistant g") */
export interface CLIGeneratorExtension {
/**
* Called if user users cli "assistant g" command
* Called if user used cli "assistant g" command
* @param {string} buildPath Path to build directory
* @return {void|Promise<void>}
*/
execute(buildPath: string): void | Promise<void>;
}

/** Interface to fulfill to register a deployment (called via cli: "assistant deploy") */
export interface CLIDeploymentExtension {
/**
* Called if user used cli "assistant deploy" command
* @param {string} buildPath Path to build directory
* @return {void|Promise<void>}
*/
@@ -10,7 +10,7 @@ export class AssistantJSSetup {

public run(app: MainApplication) {
this.container.setMainApplication(app);
this.container.runMain();
return this.container.runMain();
}

/** Returns true if internal components have already been registered */

0 comments on commit 64d2604

Please sign in to comment.
You can’t perform that action at this time.