Skip to content

Commit

Permalink
Fix/deployment (#6)
Browse files Browse the repository at this point in the history
* Fix server routes tests

* Fix Gitlab URL in Jenkinsfile

- Fix replacement URLs for Sed for API Gateway

* Fix Gitlab config to use correct branch

* Fix Gitlab credentialsId

* Remove POST body from 'prod' code

* Add testing code for using ENV variables

* Add debugging statements to node server

- For debugging in CF

* Change gitlab credentials back to bi

* Add json:true to node server request

* Add family:4 to request options in node server

- request/request-promise-native#6

* Remove hardcoded basicAuth values

* Fix search enpoint config

* Fix formQuery config, no need for & in query

* Remove debugging statements, console logs etc.

* Add logging config from sbr-ui

- Add filename to logs
- Use proper morgan logging with Winston logger

* Update Jenkinsfile with new configuration

- Build node 'GMU' label

* Add code for ShowConfetti, in server + frontend (#7)

- Copy showConfetti code from sbr-ui
  • Loading branch information
ONS-Tom authored Nov 10, 2017
1 parent 01b5842 commit a5dc1fd
Show file tree
Hide file tree
Showing 16 changed files with 144 additions and 54 deletions.
25 changes: 14 additions & 11 deletions Jenkinsfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@
@Library('jenkins-pipeline-shared@develop') _

/*
* bi-ui Jenkins Pipeline
*/
* bi-ui Jenkins Pipeline
*
* We use the 'GMU' build slave because it has the correct certificates for CF.
*/
pipeline {
agent none
options {
Expand All @@ -26,13 +28,13 @@ pipeline {
deleteDir()
checkout scm
dir('conf') {
git(url: "$GITLAB_URL/StatBusReg/bi-ui.git", credentialsId: 'bi-gitlab-id', branch: 'develop')
git(url: "$GITLAB_URL/BusinessIndex/bi-ui.git", credentialsId: 'bi-gitlab-id', branch: 'feature/manifests')
}
stash name: 'app'
}
}
stage('Install Dependancies & Build') {
agent { label 'build' }
agent { label 'GMU' }
steps {
colourText("info","Running 'npm install' and 'npm build'...")
deleteDir()
Expand Down Expand Up @@ -80,7 +82,7 @@ pipeline {
}
}
stage('Zip Project') {
agent { label 'build' }
agent { label 'GMU' }
when {
anyOf {
branch "develop"
Expand All @@ -93,7 +95,8 @@ pipeline {
colourText("info","Zipping project...")
colourText("info","Host is: ${env.CLOUD_FOUNDRY_ROUTE_SUFFIX}")
sh "sed -i -e 's|Local|dev|g' src/config/constants.js"
sh "sed -i -e 's|http://localhost:9002|https://dev-bi-api.${env.CLOUD_FOUNDRY_ROUTE_SUFFIX}|g' src/config/api-urls.js"
sh "sed -i -e 's|http://localhost:3002/auth|${api_gw/auth}|g' server/config/urls.js"
sh "sed -i -e 's|http://localhost:3001|${api_gw/bi/route}|g' server/config/urls.js"
sh "sed -i -e 's|http://localhost:3001|https://dev-bi-ui.${env.CLOUD_FOUNDRY_ROUTE_SUFFIX}|g' src/config/api-urls.js"
sh 'npm run build'
// For deployment, only need the node_modules/package.json for the server
Expand All @@ -110,7 +113,7 @@ pipeline {
}
}
stage('Deploy - DEV') {
agent { label 'build' }
agent { label 'GMU' }
when {
anyOf {
branch "develop"
Expand All @@ -125,7 +128,7 @@ pipeline {
}
}
stage('Integration Tests') {
agent { label 'build' }
agent { label 'GMU' }
when {
anyOf {
branch "release"
Expand All @@ -139,7 +142,7 @@ pipeline {
}
}
stage('Deploy - TEST') {
agent { label 'build' }
agent { label 'GMU' }
when {
anyOf {
branch "release"
Expand All @@ -154,7 +157,7 @@ pipeline {
}
}
stage('Promote to BETA?') {
agent { label 'build' }
agent { label 'GMU' }
when {
anyOf {
branch "master"
Expand All @@ -170,7 +173,7 @@ pipeline {
}
}
stage('Deploy - BETA') {
agent { label 'build' }
agent { label 'GMU' }
when {
anyOf {
branch "master"
Expand Down
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,6 @@
"express": "^4.14.0",
"halogen": "^0.2.0",
"ie-version": "^0.1.0",
"request-promise": "^4.2.2",
"istanbul": "^0.4.5",
"jasmine": "^2.5.3",
"jasmine-node": "^1.14.5",
Expand All @@ -68,6 +67,7 @@
"react-bootstrap": "^0.30.7",
"react-bootstrap-button-loader": "1.0.8",
"react-bootstrap-table": "^3.4.5",
"react-confetti": "^2.0.1",
"react-copy-to-clipboard": "^5.0.1",
"react-d3-tree": "^1.4.0",
"react-dom": "^15.5.4",
Expand All @@ -84,6 +84,7 @@
"redux-thunk": "^2.2.0",
"registers-react-library": "^1.0.0",
"request": "^2.81.0",
"request-promise": "^4.2.2",
"uuid": "^3.1.0",
"winston": "^2.4.0"
},
Expand Down
3 changes: 1 addition & 2 deletions server/apiGateway.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const rp = require('request-promise');
const timeouts = require('./config/timeouts');
const urls = require('./config/urls');
const uuidv4 = require('uuid/v4');
const logger = require('./logger');
const logger = require('./logger')(module);

const PORT = process.env.PORT || 3002;

Expand Down Expand Up @@ -133,6 +133,5 @@ function postApiEndpoint(url, postBody) {
}

app.listen(PORT, () => {
console.log(`bi-ui-mock-api-gateway listening on port ${PORT}!`);
logger.info(`bi-ui-mock-api-gateway listening on port ${PORT}!`);
});
22 changes: 11 additions & 11 deletions server/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,21 @@ const rp = require('request-promise');
const compression = require('compression');
const cache = require('./helpers/cache');
const formatDate = require('./helpers/formatDate.js');
const logger = require('./logger');
const logger = require('./logger')(module);

// To allow hot-reloading, the node server only serves the React.js index.html
// in the /build file if SERVE_HTML is true
const ENV = process.env.ENV;
const SERVE_HTML = (process.env.SERVE_HTML === 'true');

logger.info(`ENV: ${ENV}`);
logger.info(`SERVE_HTML: ${SERVE_HTML}`);

const sessions = {}; // For the user sessions
const startTime = formatDate(new Date());

const app = express();

app.use(compression()); // gzip all responses
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms'));
morgan(':remote-addr - :remote-user [:date[clf]] ":method :url HTTP/:http-version" :status :res[content-length] :response-time ms');
app.use(morgan('combined', { stream: logger.stream }));
app.use(myParser.json()); // For parsing body of POSTs

// Serve static assets (static js files for React from 'npm run build')
Expand Down Expand Up @@ -82,7 +80,7 @@ app.post('/login', (req, res) => {
timeout: timeouts.API_GW,
headers: {
'Content-Type': 'application/json',
Authorization: `${basicAuth}`
'Authorization': `${basicAuth}`
},
json: true,
body: { username }
Expand All @@ -94,17 +92,18 @@ app.post('/login', (req, res) => {
timeout: timeouts.API_GW,
headers: {
'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8',
Authorization: `${basicAuth}`
'Authorization': `${basicAuth}`
},
json: true,
body: { username }
json: true
};
}

rp(options)
.then((gatewayJson) => {
// Create user session
const accessToken = uuidv4();
// We get the showConfetti env var on every login, as it can dynamically change in CF
const showConfetti = (process.env.SHOW_CONFETTI === 'true');
sessions[accessToken] = {
key: gatewayJson.key,
role: gatewayJson.role,
Expand All @@ -116,7 +115,8 @@ app.post('/login', (req, res) => {
return res.send(JSON.stringify({
username,
accessToken,
role: gatewayJson.role
role: gatewayJson.role,
showConfetti
}));
})
.catch((err) => {
Expand Down Expand Up @@ -208,7 +208,7 @@ function postApiEndpoint(url, postBody, apiKey) {
'Authorization': apiKey,
'Content-Type': 'application/json'
},
body: JSON.stringify(postBody), // '{"updatedBy":"name","vars":{"ent_name":"name"}}',
body: JSON.stringify(postBody),
json: false
};

Expand Down
3 changes: 1 addition & 2 deletions server/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@

const fork = require('child_process').fork;
const app = require('./app');
const logger = require('./logger');
const logger = require('./logger')(module);

const PORT = process.env.PORT || 3001;

Expand All @@ -17,7 +17,6 @@ logger.info('Started Winston logger & created log file');

app.maxSockets = 500;
app.listen(PORT, () => {
console.log(`bi-ui-node-server listening on port ${PORT}!`);
logger.info(`bi-ui-node-server listening on port ${PORT}!`);
});

Expand Down
43 changes: 29 additions & 14 deletions server/logger.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,34 @@ if (!fs.existsSync(logDir)) {
fs.mkdirSync(logDir);
}

const logger = new (winston.Logger)({
transports: [
// Colorize the output to the console
new (winston.transports.Console)({
timestamp: tsFormat,
colorize: true,
}),
new (winston.transports.File)({
filename: `${logDir}/bi-ui-node-server-logs.log`,
timestamp: tsFormat,
level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
}),
],
});
const logger = (module) => {
const path = module.filename.split('/').slice(-2).join('/');

const winstonLogger = new (winston.Logger)({
transports: [
// Colorize the output to the console
new (winston.transports.Console)({
timestamp: tsFormat,
colorize: true,
label: path,
}),
new (winston.transports.File)({
filename: `${logDir}/bi-ui-node-server-logs.log`,
timestamp: tsFormat,
level: process.env.NODE_ENV === 'development' ? 'debug' : 'info',
label: path,
}),
],
});

// Morgan appends an extra \n, so we need to remove it
winstonLogger.stream = {
write: (message, encoding) => {
winstonLogger.info(message.substring(0, message.lastIndexOf('\n')));
},
};

return winstonLogger;
};

module.exports = logger;
12 changes: 11 additions & 1 deletion src/actions/LoginActions.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

import { browserHistory } from 'react-router';
import base64 from 'base-64';
import { SET_AUTH, USER_LOGOUT, SENDING_REQUEST, SET_ERROR_MESSAGE, SET_USER_DETAILS } from '../constants/LoginConstants';
import { SET_AUTH, SET_CONFETTI, USER_LOGOUT, SENDING_REQUEST, SET_ERROR_MESSAGE, SET_USER_DETAILS } from '../constants/LoginConstants';
import * as errorMessages from '../constants/MessageConstants';
import auth from '../utils/auth';
import { getUiInfo, getApiInfo } from '../actions/InfoActions';
Expand Down Expand Up @@ -53,6 +53,7 @@ export function login(username, password) {
dispatch(sendingRequest(false));
dispatch(setAuthState(success));
if (success) {
dispatch(setConfetti(data.showConfetti));
// If the login worked, forward the user to the dashboard and clear the form
dispatch(setUserState({
username,
Expand Down Expand Up @@ -133,6 +134,15 @@ export function logout() {
};
}

/**
* Sets the user details state of the application (username, role)
* @param {boolean} show Whether or not to show the the confetti
* @return {object} Formatted action for the reducer to handle
*/
export function setConfetti(show) {
return { type: SET_CONFETTI, show };
}

export function resetState() {
return { type: USER_LOGOUT };
}
Expand Down
51 changes: 51 additions & 0 deletions src/components/Confetti.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import React from 'react';
import PropTypes from 'prop-types';
import Confetti from 'react-confetti';
import { connect } from 'react-redux';

class ShowConfetti extends React.Component {
constructor(props) {
super(props);
this.state = {
opacity: 1,
count: 0,
};
this.tick = this.tick.bind(this);
}
componentDidMount() {
if (this.props.showConfetti) {
this.interval = setInterval(this.tick, 250);
}
}
componentWillUnmount() {
clearInterval(this.interval);
}
tick() {
if (this.state.count > (this.props.seconds / 0.25)) {
clearInterval(this.interval);
}
this.setState({ count: this.state.count + 1, opacity: this.state.opacity - (0.25 / this.props.seconds) });
}
render() {
return (
<div>
{(this.state.count < (this.props.seconds / 0.25) && this.props.showConfetti) &&
<Confetti opacity={this.state.opacity} width={`${window.innerWidth}px`} height={`${window.innerHeight}px`} />
}
</div>
);
}
}

ShowConfetti.propTypes = {
showConfetti: PropTypes.bool.isRequired,
seconds: PropTypes.number.isRequired,
};

function select(state) {
return {
showConfetti: state.login.showConfetti,
};
}

export default connect(select)(ShowConfetti);
2 changes: 1 addition & 1 deletion src/config/api-urls.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
const apiUrls = {
AUTH_URL: 'http://localhost:3001',
REROUTE_URL: 'http://localhost:3001/api',
SEARCH_ENDPOINT: 'search?query=',
SEARCH_ENDPOINT: 'search/',
API_VERSION: 'v1',
};

Expand Down
1 change: 1 addition & 0 deletions src/config/constants.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const constants = {
ENV: 'Local',
SHOW_CONFETTI_TIME: 10,
};

export default constants;
2 changes: 1 addition & 1 deletion src/config/form-query.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ const formQuery = {
SEPERATOR: ':',
ES_CONCAT: 'AND',
LIMIT: '?limit=10000',
END_SEPERATOR: '&',
END_SEPERATOR: '',
};

export default formQuery;
1 change: 1 addition & 0 deletions src/constants/LoginConstants.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ export const SET_AUTH = 'SET_AUTH';
export const SENDING_REQUEST = 'SENDING_REQUEST';
export const SET_ERROR_MESSAGE = 'SET_ERROR_MESSAGE';
export const USER_LOGOUT = 'USER_LOGOUT';
export const SET_CONFETTI = 'SET_CONFETTI';
Loading

0 comments on commit a5dc1fd

Please sign in to comment.