Skip to content
This repository has been archived by the owner on Dec 8, 2022. It is now read-only.

Skyux 'pact' CLI command #319

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
f603c82
trying to bypass some stuff
Oct 10, 2017
a033aea
overriding some methods for testing
Oct 10, 2017
fd6b4d1
merging with master
Oct 17, 2017
8d2d768
workring on changes to configs and cli commands. Still need to get c…
Oct 18, 2017
6da0cfb
dynamically adding pact ports
Oct 19, 2017
de07822
Merge branch 'master' of https://github.com/blackbaud/skyux-builder
Oct 19, 2017
16d4b26
adding more karma config settings, adding a service for use my consum…
Oct 25, 2017
786ab3d
Merge branch 'master' of https://github.com/blackbaud/skyux-builder
Oct 25, 2017
224bd06
Adding documentation, watch option for command, and making interface …
Oct 30, 2017
1abd6bc
supporting looking for only pact-spec files
Oct 30, 2017
004b726
respecting a bunch of jslint errors when running npm run test
Oct 30, 2017
f40192f
optionally let use define directory for pact json and pact logs
Oct 31, 2017
fd0d91d
Merge branch 'master' into master
blackbaud-joshlandi Oct 31, 2017
dbe6d27
changing import statement
Oct 31, 2017
64eeacb
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 1, 2017
f34ff9d
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 2, 2017
fcd96e5
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 2, 2017
c9c8a11
formatting changes and moving dynamically set config settings to runtime
Nov 3, 2017
e4460aa
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 3, 2017
1571f46
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 3, 2017
63edd3b
karma-pact depends on the latest pact-node, but our config doesn't en…
Nov 6, 2017
fb44a40
letting karma-pact take care of it's pact-node dependency. Still nee…
Nov 6, 2017
ba4eee4
cleaning up some formatting so build passes
Nov 6, 2017
edf57f0
noticed ports weren't being retreived across processes. portfinder d…
Nov 8, 2017
89a03af
adding spec file for pacts
Nov 14, 2017
0ef0555
writing tests for pact command, made some changes based on my finding…
Nov 15, 2017
0fb6bfd
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 15, 2017
fbac696
tests on karma config, and further changes for thing found during tes…
Nov 16, 2017
7f9256e
Merge branch 'jlandi-pact-cli' of https://github.com/blackbaud-joshla…
Nov 16, 2017
209927c
for whatever reason, not including this causes errors.
Nov 16, 2017
048a877
100% coverage
Nov 16, 2017
009ee52
some linting errors getting fixed
Nov 16, 2017
7183507
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 29, 2017
d83fa73
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Nov 29, 2017
faab3f7
removing that one extra line
Nov 30, 2017
32de8f8
thinking not stopping all mocks here could've caused the issue
Nov 30, 2017
1892622
weird merge conflict that didn't cause build to fail, and removing ca…
Dec 5, 2017
8fc35c5
possibly no need to have the pact-web package
Dec 6, 2017
424e6fe
right, this test needs to be updated
Dec 6, 2017
cc87b63
Merge branch 'master' into jlandi-pact-cli
blackbaud-joshlandi Dec 8, 2017
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
153 changes: 153 additions & 0 deletions cli/pact.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*jslint node: true */
'use strict';

/**
* Spawns the skyux pact command.
* @name pact
*/
function pact(command, argv) {
const async = require('async');
const configResolver = require('./utils/config-resolver');
const karma = require('karma');
const Server = karma.Server;
const portfinder = require('portfinder');
const url = require('url');
const logger = require('../utils/logger');
const tsLinter = require('./utils/ts-linter');
const skyPagesConfigUtil = require('../config/sky-pages/sky-pages.config');
const pactServers = require('../utils/pact-servers');
let skyPagesConfig = skyPagesConfigUtil.getSkyPagesConfig(command);
let http = require('http');
let httpProxy = require('http-proxy');

argv = argv || process.argv;
argv.command = command;

let pactPortSeries = [];
let consumedPorts = [];
// get a free port for every config entry, plus one for the proxy
if (!skyPagesConfig.skyux.pacts) {
logger.error('skyux pact failed! pacts does not exist on configuration file.');
process.exit();
}

let getAsyncFunction = (callback) => {

// ports are not consumed until karma starts, so need to keep track of future consumed ports
portfinder.getPortPromise(
{ port: consumedPorts.length === 0 ? 8000 : Math.max(consumedPorts) + 1 }
)
.then((port) => {
consumedPorts.push(port);
callback(null, port);
})
.catch((error) => {
callback(error, null);
});

};

for (let i = 0; i < skyPagesConfig.skyux.pacts.length + 1; i++) {

pactPortSeries.push(getAsyncFunction);

}

// make sure ports are resolved in order
async.series(pactPortSeries,
(err, ports) => {
if (err) {
logger.error(err);
process.exit();
}

for (let i = 0; i < skyPagesConfig.skyux.pacts.length; i++) {

let serverHost = (skyPagesConfig.skyux.pacts[i].host || 'localhost');
let serverPort = (skyPagesConfig.skyux.pacts[i].port || ports[i]);
// saving pact server information so it can carry over into karma config
pactServers
.savePactServer(skyPagesConfig.skyux.pacts[i].provider, serverHost, serverPort);
}

let proxy = httpProxy.createProxyServer({});

// proxy requests to pact server to contain actual host url rather than the karma url
proxy.on('proxyReq', function (proxyReq) {
let origin;
origin = (skyPagesConfig.skyux.host || {}).url || 'https://host.nxt.blackbaud.com';
proxyReq.setHeader('Origin', origin);
});
// revert CORS header value back to karma url so that requests are successful
proxy.on('proxyRes', function (proxyRes, req) {
proxyRes.headers['Access-Control-Allow-Origin'] = req.headers.origin;
});

http.createServer((req, res) => {

// provider is part of path so that consuming app can make requests to multiple pact
// servers from one proxy server. Use that value to identify proper pact server and then
// remove from request url.
let provider = url.parse(req.url).pathname.split('/')[1];
req.url = req.url.split(provider)[1];
if (Object.keys(pactServers.getAllPactServers()).indexOf(provider) !== -1) {
proxy.web(req, res, {
target: pactServers.getPactServer(provider).fullUrl
});
} else {
logger
.error(`Pact proxy path is invalid. Expected format is base/provider-name/api-path.`);
}
})
.on('connect', () => {
logger
.info(
`Pact proxy server successfully started on http://localhost:${ports[ports.length - 1]}`
);
})
.listen(ports[ports.length - 1], 'localhost');

// for use by consuming app
pactServers.savePactProxyServer(`http://localhost:${ports[ports.length - 1]}`);

const karmaConfigUtil = karma.config;
const karmaConfigPath = configResolver.resolve(command, argv);
const karmaConfig = karmaConfigUtil.parseConfig(karmaConfigPath);

let lintResult;

const onRunStart = () => {
lintResult = tsLinter.lintSync();
};

const onRunComplete = () => {
if (lintResult && lintResult.exitCode > 0) {
// Pull the logger out of the execution stream to let it print
// after karma's coverage reporter.
setTimeout(() => {
logger.error('Process failed due to linting errors:');
lintResult.errors.forEach(error => logger.error(error));
}, 10);
}
};

const onExit = (exitCode) => {
if (exitCode === 0) {
if (lintResult) {
exitCode = lintResult.exitCode;
}
}

logger.info(`Karma has exited with ${exitCode}.`);
process.exit(exitCode);
};

const server = new Server(karmaConfig, onExit);
server.on('run_start', onRunStart);
server.on('run_complete', onRunComplete);
server.start();
});

}

module.exports = pact;
48 changes: 48 additions & 0 deletions config/karma/pact.karma.conf.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*jshint node: true*/
'use strict';

/**
* Requires the shared karma config and sets any local properties.
* @name getConfig
* @param {Object} config
*/
function getConfig(config) {
const minimist = require('minimist');
const argv = minimist(process.argv.slice(2));
require(`./${argv.watch ? 'watch' : 'test'}.karma.conf`)(config);
let skyPagesConfig = require('../sky-pages/sky-pages.config').getSkyPagesConfig(argv._[0]);
let testWebpackConfig = require('../webpack/test.webpack.config');
const logger = require('../../utils/logger');
const path = require('path');
const pactServers = require('../../utils/pact-servers');

skyPagesConfig.runtime.pactConfig = {};
skyPagesConfig.runtime.pactConfig.providers = pactServers.getAllPactServers();
skyPagesConfig.runtime.pactConfig.pactProxyServer = pactServers.getPactProxyServer();

if (skyPagesConfig.skyux.pacts) {
var i = 0;
skyPagesConfig.skyux.pacts.forEach((pact) => {
// set pact settings not specified in config file
pact.log = pact.log || path.resolve(process.cwd(), 'logs', `pact-${pact.provider}.log`);
pact.dir = pact.dir || path.resolve(process.cwd(), 'pacts');
pact.host = pactServers.getPactServer(pact.provider).host;
pact.port = pactServers.getPactServer(pact.provider).port;
i++;
});
} else {
logger.error('No pact entry in configuration!');
}

config.set({
frameworks: config.frameworks.concat('pact'),
files: config.files.concat(path.resolve(process.cwd(), 'node_modules/pact/src', `pact-web.js`)),
pact: skyPagesConfig.skyux.pacts,
plugins: config.plugins.concat('@pact-foundation/karma-pact'),
webpack: testWebpackConfig.getWebpackConfig(skyPagesConfig, argv)

});

}

module.exports = getConfig;
1 change: 0 additions & 1 deletion config/karma/shared.karma.conf.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ function getConfig(config) {
// This file is spawned so we'll need to read the args again
const minimist = require('minimist');
const argv = minimist(process.argv.slice(2));

const path = require('path');
let testWebpackConfig = require('../webpack/test.webpack.config');
let remapIstanbul = require('remap-istanbul');
Expand Down
1 change: 0 additions & 1 deletion config/webpack/test.webpack.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,6 @@ function outPath() {
function getWebpackConfig(skyPagesConfig, argv) {
const runCoverage = (!argv || argv.coverage !== false);
skyPagesConfig.runtime.includeRouteModule = false;

const ENV = process.env.ENV = process.env.NODE_ENV = 'test';
const srcPath = path.resolve(process.cwd(), 'src', 'app');

Expand Down
3 changes: 3 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ module.exports = {
case 'lint':
require('./cli/lint')();
break;
case 'pact':
require('./cli/pact')(command, argv);
break;
case 'test':
case 'watch':
require('./cli/test')(command, argv);
Expand Down
26 changes: 22 additions & 4 deletions lib/sky-pages-module-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@ function getSource(skyAppConfig) {
let runtimeProviders = [
'SkyAppWindowRef',
'SkyAppStyleLoader',
'SkyAuthTokenProvider',
`{
provide: SkyAppConfig,
deps: [
Expand All @@ -67,6 +66,25 @@ function getSource(skyAppConfig) {
'SkyAppViewportService'
];

let authTokenProvider = 'SkyAuthTokenProvider';

if (skyAppConfig.runtime.command === 'pact') {
runtimeProviders
.push(`{
provide: SkyPactService,
useClass: SkyPactService,
deps: [SkyAppConfig]
}`);
runtimeImports.push('SkyPactAuthTokenProvider');
runtimeImports.push('SkyPactService');
authTokenProvider = `{
provide: SkyAuthTokenProvider,
useClass: SkyPactAuthTokenProvider
}`;
}

runtimeProviders.push(authTokenProvider);

let nodeModuleImports = [
`import { Component, NgModule, OnDestroy, OnInit } from '@angular/core';`,
`import { CommonModule } from '@angular/common';`,
Expand Down Expand Up @@ -122,13 +140,13 @@ function getSource(skyAppConfig) {
switch (skyAppConfig.runtime.command) {
case 'build':
enableProdMode =
`import { enableProdMode } from '@angular/core';
`import { enableProdMode } from '@angular/core';
enableProdMode();`;
break;

case 'e2e':
useMockAuth =
`import { BBAuth } from '@blackbaud/auth-client';
`import { BBAuth } from '@blackbaud/auth-client';
BBAuth.mock = true;
`;
break;
Expand All @@ -137,7 +155,7 @@ BBAuth.mock = true;
let useHashRouting = skyAppConfig.skyux.useHashRouting === true;

let moduleSource =
`${useMockAuth}
`${useMockAuth}

${nodeModuleImports.join('\n')}

Expand Down
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,8 @@
"ngc-webpack": "3.0.0",
"node-sass": "4.5.3",
"open": "0.0.5",
"@pact-foundation/karma-pact": "2.1.1",
"pact": "4.2.1",
"portfinder": "1.0.13",
"progress-bar-webpack-plugin": "1.9.3",
"protractor": "5.1.2",
Expand Down
15 changes: 14 additions & 1 deletion runtime/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,25 @@ export interface RuntimeConfigApp {
template: string;
}

export class SkyuxPactConfig {
public providers?: {
[provider: string]: {
host?: string;
port?: string;
fullUrl?: string;
}
};
public pactProxyServer?: string;
}

export interface RuntimeConfig {
app: RuntimeConfigApp;
command?: string; // Dynamically added in "higher up" webpacks
componentsPattern: string;
componentsIgnorePattern: string;
handle404?: boolean; // Dynamically added in sky-pages-module-generator.js
includeRouteModule: boolean;
pactConfig?: SkyuxPactConfig;
params: SkyAppRuntimeConfigParams;
routes?: Object[]; // Dynamically added in sky-pages-module-generator.js
routesPattern: string;
Expand All @@ -41,7 +53,7 @@ export interface SkyuxConfigHost {
}

export interface SkyuxConfig {
a11y?: SkyuxConfigA11y|boolean;
a11y?: SkyuxConfigA11y | boolean;
app?: SkyuxConfigApp;
appSettings?: any;
auth?: boolean;
Expand All @@ -53,6 +65,7 @@ export interface SkyuxConfig {
importPath?: string;
mode?: string;
name?: string;
pacts?: any[];
params?: SkyuxConfigParams; // List of allowed params
plugins?: string[];
redirects?: any;
Expand Down
2 changes: 2 additions & 0 deletions runtime/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
export * from './assets.service';
export * from './auth-http';
export * from './auth-token-provider';
export * from './pact-auth-token-provider';
export * from './pact.service';
export * from './bootstrapper';
export * from './config';
export * from './params';
Expand Down
9 changes: 9 additions & 0 deletions runtime/pact-auth-token-provider.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { BBAuthGetTokenArgs } from '@blackbaud/auth-client';

export class SkyPactAuthTokenProvider {

public getToken(args?: BBAuthGetTokenArgs): Promise<string> {
return Promise.resolve('mock_access_token_auth-client@blackbaud.com');
}

}
Loading