Skip to content

Commit

Permalink
Merge pull request #149 from Eastern-Research-Group/develop
Browse files Browse the repository at this point in the history
Deploy to staging.
  • Loading branch information
coobr01 authored Oct 28, 2024
2 parents 00e24a4 + cede650 commit 1960cfb
Show file tree
Hide file tree
Showing 13 changed files with 4,686 additions and 1,248 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,7 @@ jobs:
# Run CloudFoundry/Cloud.gov deployment
- name: Set up Cloud Foundry CLI
run: |
curl -v -L -o cf-cli_amd64.deb 'https://cli.run.pivotal.io/stable?release=debian64&version=v7&source=github'
curl -v -L -o cf-cli_amd64.deb 'https://packages.cloudfoundry.org/stable?release=debian64&version=v7&source=github'
sudo dpkg -i cf-cli_amd64.deb
cf -v
cf api https://api.fr.cloud.gov
Expand Down
41 changes: 41 additions & 0 deletions .github/workflows/production.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Production Build

# Controls when the action will run.
on:
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:

# Set shared environment variables
env:
APP_VERSION: 2.4.0

# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
build:
# The type of runner that the job will run on
runs-on: ubuntu-latest
environment: production

# Steps represent a sequence of tasks that will be executed as part of the job
steps:
# Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it
- uses: actions/checkout@v4

# Set up node and npm
- uses: actions/setup-node@v4
with:
node-version: "20"

- name: Install dependencies
run: npm install --omit=dev
working-directory: app

- name: Remove unnecessary server app files
run: rm -rf prettier.config.js manifest-dev.yml manifest-staging.yml app/tests
working-directory: app

- name: Create production artifact
uses: actions/upload-artifact@v4
with:
name: lew_v${{ env.APP_VERSION }}
path: app
2 changes: 1 addition & 1 deletion .github/workflows/staging.yml
Original file line number Diff line number Diff line change
Expand Up @@ -80,7 +80,7 @@ jobs:
# Run CloudFoundry/Cloud.gov deployment
- name: Set up Cloud Foundry CLI
run: |
curl -v -L -o cf-cli_amd64.deb 'https://cli.run.pivotal.io/stable?release=debian64&version=v7&source=github'
curl -v -L -o cf-cli_amd64.deb 'https://packages.cloudfoundry.org/stable?release=debian64&version=v7&source=github'
sudo dpkg -i cf-cli_amd64.deb
cf -v
cf api https://api.fr.cloud.gov
Expand Down
12 changes: 11 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,14 @@ npm-debug.log
.DS_Store

# Visual Studio 2015/2017 cache/options directory
.vs/
.vs/

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage
*.lcov

# nyc test coverage
.nyc_output
5 changes: 0 additions & 5 deletions .husky/pre-commit

This file was deleted.

2 changes: 2 additions & 0 deletions app/.husky/pre-commit
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
cd app
lint-staged
13 changes: 13 additions & 0 deletions app/.nycrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"all": true,
"include": [
"app/**/*.{ts,js}"
],
"exclude": [
"**/node_modules/**",
"**/coverage/**",
"**/epa-template-files/**",
"**/tests/**",
"**/api-docs/**"
]
}
111 changes: 111 additions & 0 deletions app/app/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
const path = require('path');
const express = require('express');
const helmet = require('helmet');
const noCache = require('nocache');
const cors = require('cors');
const favicon = require('serve-favicon');
const basicAuth = require('express-basic-auth');
const { getEnvironment } = require('./server/utilities/environment');
const logger = require('./server/utilities/logger');
const log = logger.logger;

const app = express();

app.use(
helmet({
contentSecurityPolicy: false,
crossOriginEmbedderPolicy: false,
}),
);
app.use(noCache());
app.use(
helmet.hsts({
maxAge: 31536000,
}),
);

app.use(cors());

/****************************************************************
Which environment
****************************************************************/
const { isLocal, isTest, isDevelopment, isStaging } = getEnvironment();

if (isLocal) {
log.info('Environment = local');
app.enable('isLocal');
} else if (isTest) {
log.info('Environment = test');
app.enable('isTest');
}

if (isDevelopment) log.info('Environment = development');
if (isStaging) log.info('Environment = staging');
if (!isLocal && !isTest && !isDevelopment && !isStaging)
log.info('Environment = preprod or production');

/****************************************************************
Setup basic auth for non-staging and non-production
****************************************************************/
if (isDevelopment || isStaging) {
if (
process.env.LEW_BASIC_AUTH_USER_NAME == null ||
process.env.LEW_BASIC_AUTH_USER_PWD == null
) {
log.error(
'Either the basic LEW user name or password environmental variable is not set.',
);
}

const user_json =
'{"' +
process.env.LEW_BASIC_AUTH_USER_NAME +
'" : "' +
process.env.LEW_BASIC_AUTH_USER_PWD +
'"}';
const user_obj = JSON.parse(user_json);

app.use(
basicAuth({
users: user_obj,
challenge: true,
unauthorizedResponse: getUnauthorizedResponse,
}),
);
}

function getUnauthorizedResponse(req) {
return req.auth ? 'Invalid credentials' : 'No credentials provided';
}

/****************************************************************
Setup server and routes
****************************************************************/
app.use(
'/',
express.static(path.join(__dirname, 'public'), { index: ['index.html'] }),
);
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

/****************************************************************
Enable CORS/Preflight/OPTIONS request
****************************************************************/
app.options('*', cors());

/****************************************************************
Custom application routes
****************************************************************/
require('./server/routes/index')(app);

/****************************************************************
Worst case error handling for 404 and 500 issues
****************************************************************/
app.use(function (req, res, next) {
res.status(404).sendFile(path.join(__dirname, 'public', '404.html'));
});

app.use(function (err, req, res, next) {
res.status(500).sendFile(path.join(__dirname, 'public', '500.html'));
});

module.exports = app;
128 changes: 16 additions & 112 deletions app/app/server.js
Original file line number Diff line number Diff line change
@@ -1,129 +1,33 @@
const express = require('express');
const helmet = require('helmet');
const noCache = require('nocache');
const cors = require('cors');
const favicon = require('serve-favicon');
const basicAuth = require('express-basic-auth');
const path = require('path');
const logger = require('./server/utilities/logger.js');

const app = express();
app.use(
helmet({
contentSecurityPolicy: false,
crossOriginEmbedderPolicy: false,
}),
);
app.use(noCache());
app.use(
helmet.hsts({
maxAge: 31536000,
}),
);
app.use(cors());
const logger = require('./server/utilities/logger');
const log = logger.logger;
const browserSyncPort = 9091;
let port = process.env.PORT || 9090;
const browserSync_port = 9091;

/****************************************************************
Which environment
****************************************************************/
let isLocal = false;
let isDevelopment = false;
let isStaging = false;

if (process.env.NODE_ENV) {
isLocal = 'local' === process.env.NODE_ENV.toLowerCase();
isDevelopment = 'development' === process.env.NODE_ENV.toLowerCase();
isStaging = 'staging' === process.env.NODE_ENV.toLowerCase();
}

if (isLocal) log.info('Environment = local');
if (isDevelopment) log.info('Environment = development');
if (isStaging) log.info('Environment = staging');
if (!isLocal && !isDevelopment && !isStaging)
log.info('Environment = staging or production');

/****************************************************************
Setup basic auth for non-staging and non-production
****************************************************************/
if (isDevelopment || isStaging) {
if (
process.env.LEW_BASIC_AUTH_USER_NAME == null ||
process.env.LEW_BASIC_AUTH_USER_PWD == null
) {
log.error(
'Either the basic LEW user name or password environmental variable is not set.',
);
}

const user_json =
'{"' +
process.env.LEW_BASIC_AUTH_USER_NAME +
'" : "' +
process.env.LEW_BASIC_AUTH_USER_PWD +
'"}';
const user_obj = JSON.parse(user_json);

app.use(
basicAuth({
users: user_obj,
challenge: true,
unauthorizedResponse: getUnauthorizedResponse,
}),
);
}

function getUnauthorizedResponse(req) {
return req.auth ? 'Invalid credentials' : 'No credentials provided';
const { isLocal } = require('./server/utilities/environment');

let app;
try {
app = require('./app');
} catch (err) {
log.error('Error starting server: ' + err.message);
process.exit();
}

/****************************************************************
Setup server and routes
****************************************************************/
app.use(
'/',
express.static(path.join(__dirname, 'public'), { index: ['index.html'] }),
);
app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));

/****************************************************************
Enable CORS/Preflight/OPTIONS request
****************************************************************/
app.options('*', cors());

/****************************************************************
Custom application routes
****************************************************************/
require('./server/routes/index')(app);

/****************************************************************
Worst case error handling for 404 and 500 issues
****************************************************************/
app.use(function (req, res, next) {
res.status(404).sendFile(path.join(__dirname, 'public', '400.html'));
});

app.use(function (err, req, res, next) {
res.status(500).sendFile(path.join(__dirname, 'public', '500.html'));
});

//For local testing of the production flow, use the same port as browersync to avoid
//different port usage to confuse testers/developers
if (port === 9090 && isLocal === false) {
port = browserSync_port;
}
// for local testing of the production flow, use the same port as browersync to avoid
// different port usage to confuse testers/developers
if (port === 9090 && !isLocal) port = browserSyncPort;

app.listen(port, function () {
if (isLocal) {
const browserSync = require('browser-sync');

log.info(`Application listening on port ${browserSync_port}`);
log.info(`Application listening on port ${browserSyncPort}`);

browserSync({
files: [path.join(__dirname, '/public/**')],
online: false,
open: false,
port: browserSync_port,
port: browserSyncPort,
proxy: 'localhost:' + port,
ui: false,
});
Expand Down
24 changes: 24 additions & 0 deletions app/app/server/utilities/environment.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
// determine which environment we are in
exports.getEnvironment = function () {
let isLocal = false;
let isTest = false;
let isDevelopment = false;
let isStaging = false;
let isProduction = false;

if (process.env.NODE_ENV) {
isLocal = 'local' === process.env.NODE_ENV.toLowerCase();
isTest = 'test' === process.env.NODE_ENV.toLowerCase();
isDevelopment = 'development' === process.env.NODE_ENV.toLowerCase();
isStaging = 'staging' === process.env.NODE_ENV.toLowerCase();
isProduction = 'production' === process.env.NODE_ENV.toLowerCase();
}

return {
isLocal,
isTest,
isDevelopment,
isStaging,
isProduction,
};
};
Loading

0 comments on commit 1960cfb

Please sign in to comment.