forked from blackbaud/skyux-builder
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Skyux 'pact' CLI command (blackbaud#319)
* trying to bypass some stuff * overriding some methods for testing * workring on changes to configs and cli commands. Still need to get config and tokenProvider to be overriden * dynamically adding pact ports * adding more karma config settings, adding a service for use my consuming apps, and a util to help with passing information to user in AppConfig * Adding documentation, watch option for command, and making interface for pact settings in config file * supporting looking for only pact-spec files * respecting a bunch of jslint errors when running npm run test * optionally let use define directory for pact json and pact logs * changing import statement * formatting changes and moving dynamically set config settings to runtime * karma-pact depends on the latest pact-node, but our config doesn't ensure the latest is updated. * letting karma-pact take care of it's pact-node dependency. Still need pact as the DSL and pact-web * cleaning up some formatting so build passes * noticed ports weren't being retreived across processes. portfinder doesn't look at host 0:0:0:0 and also promises need to be resolved sequentially to prevent promises resolving on same port since they don't get consumed until after portfinder starts. * adding spec file for pacts * writing tests for pact command, made some changes based on my findings during testing. * tests on karma config, and further changes for thing found during testing * for whatever reason, not including this causes errors. * 100% coverage * some linting errors getting fixed * removing that one extra line * thinking not stopping all mocks here could've caused the issue * weird merge conflict that didn't cause build to fail, and removing carats from package.json * possibly no need to have the pact-web package * right, this test needs to be updated
- Loading branch information
1 parent
1b51168
commit de1fd17
Showing
18 changed files
with
1,268 additions
and
14 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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'); | ||
} | ||
|
||
} |
Oops, something went wrong.