Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add run command for Heroku #206

Merged
merged 7 commits into from
Sep 23, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
2 changes: 1 addition & 1 deletion apps/backend/.env-example
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
HEIMDALL_SERVER_PORT=<Port that the app starts up on (if nothing is provided, defaults to 3000)>
PORT=<Port that the app starts up on (if nothing is provided, defaults to 3000)>
DATABASE_HOST=<Hostname where the database exists (if nothing is provided, defaults to 127.0.0.1)>
DATABASE_PORT=<Port to connect to the database (if nothing is provided, defaults to 5432)>
DATABASE_USERNAME=<Username to authenticate to the database (if nothing is provided, defaults to postgres)>
Expand Down
2 changes: 1 addition & 1 deletion apps/backend/.sequelizerc
Original file line number Diff line number Diff line change
Expand Up @@ -12,5 +12,5 @@ const config = {
};

module.exports = {
url: `${config.dialect}://${config.username}:${config.password}:@${config.host}:${config.port}/${config.database}`
url: process.env.DATABASE_URL || `${config.dialect}://${config.username}:${config.password}:@${config.host}:${config.port}/${config.database}`
};
4 changes: 2 additions & 2 deletions apps/backend/jest-puppeteer.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ module.exports = {
}
},
server: {
command: 'npm run start:prod',
port: process.env.HEIMDALL_SERVER_PORT || 3000,
command: 'npm run start',
port: process.env.PORT || 3000,
launchTimeout: 20000
}
};
3 changes: 1 addition & 2 deletions apps/backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,9 @@
"scripts": {
"prebuild": "rimraf ../../dist/server",
"build": "nest build",
"start": "nest start",
"start:dev": "nest start --watch",
"start:debug": "nest start --debug --watch",
"start:prod": "node ../../dist/server/main",
"start": "node ../../dist/server/main",
"lint": "eslint \"{src,migrations,seeders,test}/**/*.ts\" --fix",
"lint:ci": "eslint \"{src,migrations,seeders,test}/**/*.ts\" --max-warnings 0",
"test": "jest --silent",
Expand Down
41 changes: 36 additions & 5 deletions apps/backend/src/config/config.service.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@ import mock from 'mock-fs';
import {ConfigService} from './config.service';
import {
ENV_MOCK_FILE,
SIMPLE_ENV_MOCK_FILE
SIMPLE_ENV_MOCK_FILE,
DATABASE_URL_MOCK_ENV
} from '../../test/constants/env-test.constant';

/* If you run the test without --silent , you need to add console.log() before you mock out the
Expand All @@ -11,7 +12,7 @@ found at https://github.com/tschaub/mock-fs/issues/234).
If you run the test with --silent (which we do by default), you don't need the log statement. */
describe('Config Service', () => {
beforeAll(async () => {
// console.log();
console.log();
// Used as an empty file system
mock({
// No files created (.env file does not exist yet)
Expand Down Expand Up @@ -50,7 +51,7 @@ describe('Config Service', () => {

it('should return the correct database name', () => {
const configService = new ConfigService();
expect(configService.get('HEIMDALL_SERVER_PORT')).toEqual('8000');
expect(configService.get('PORT')).toEqual('8000');
expect(configService.get('DATABASE_HOST')).toEqual('localhost');
expect(configService.get('DATABASE_PORT')).toEqual('5432');
expect(configService.get('DATABASE_USERNAME')).toEqual('postgres');
Expand Down Expand Up @@ -79,8 +80,7 @@ describe('Config Service', () => {

it('should return the correct database name', () => {
const configService = new ConfigService();
console.log(process.env);
expect(configService.get('HEIMDALL_SERVER_PORT')).toEqual('8001');
expect(configService.get('PORT')).toEqual('8001');
});

it('should return undefined because env variable does not exist', () => {
Expand All @@ -89,6 +89,29 @@ describe('Config Service', () => {
});
});

describe('When using DATABASE_URL', () => {
beforeAll(() => {
mock({
'.env': DATABASE_URL_MOCK_ENV
});
});

it('should correctly parse DATABASE_URL into its components', () => {
const configService = new ConfigService();
expect(configService.get('DATABASE_HOST')).toEqual(
'ec2-00-000-11-123.compute-1.amazonaws.com'
);
expect(configService.get('DATABASE_PORT')).toEqual('5432');
expect(configService.get('DATABASE_USERNAME')).toEqual(
'abcdefghijk123456'
);
expect(configService.get('DATABASE_PASSWORD')).toEqual(
'000011112222333344455556666777778889999aaaabbbbccccddddeeeffff'
);
expect(configService.get('DATABASE_NAME')).toEqual('database01');
});
});

describe('Tests for thrown errors', () => {
it('should throw an EACCES error', () => {
expect.assertions(1);
Expand All @@ -115,6 +138,14 @@ describe('Config Service', () => {
});
});

describe('Set', () => {
it('should set a key value', () => {
const configService = new ConfigService();
configService.set('test', 'value');
expect(configService.get('test')).toBe('value');
});
});

afterAll(() => {
// Restore the fs binding to the real file system
mock.restore();
Expand Down
54 changes: 44 additions & 10 deletions apps/backend/src/config/config.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import * as dotenv from 'dotenv';
import * as fs from 'fs';

export class ConfigService {
private readonly envConfig: {[key: string]: string};
private envConfig: {[key: string]: string};

constructor() {
console.log('Attempting to read configuration file `.env`!');
Expand All @@ -11,6 +11,7 @@ export class ConfigService {
console.log('Read config!');
} catch (error) {
if (error.code === 'ENOENT') {
this.envConfig = {};
// File probably does not exist
console.log('Unable to read configuration file `.env`!');
console.log(
Expand All @@ -21,17 +22,50 @@ export class ConfigService {
throw error;
}
}
if (this.parseDatabaseUrl()) {
console.log(
'DATABASE_URL parsed into smaller components (i.e. DATABASE_USER)'
);
}
}

get(key: string): string | undefined {
try {
return this.envConfig[key];
} catch (error) {
if (error instanceof TypeError) {
return process.env[key];
} else {
throw error;
}
private parseDatabaseUrl(): boolean {
if (!this.get('DATABASE_URL')) {
return false;
} else {
const url = this.get('DATABASE_URL');
const pattern = /^(?:([^:\/?#\s]+):\/{2})?(?:([^@\/?#\s]+)@)?([^\/?#\s]+)?(?:\/([^?#\s]*))?(?:[?]([^#\s]+))?\S*$/;
const matches = url.match(pattern);

this.set(
'DATABASE_USERNAME',
matches[2] !== undefined ? matches[2].split(':')[0] : undefined
);
this.set(
'DATABASE_PASSWORD',
matches[2] !== undefined ? matches[2].split(':')[1] : undefined
);
this.set(
'DATABASE_HOST',
matches[3] !== undefined ? matches[3].split(/:(?=\d+$)/)[0] : undefined
);
this.set(
'DATABASE_NAME',
matches[4] !== undefined ? matches[4].split('/')[0] : undefined
);
this.set(
'DATABASE_PORT',
matches[3] !== undefined ? matches[3].split(/:(?=\d+$)/)[1] : undefined
);
return true;
}
}

set(key: string, value: string) {
this.envConfig[key] = value;
}

get(key: string): string | undefined {
return process.env[key] || this.envConfig[key];
}
}
3 changes: 1 addition & 2 deletions apps/backend/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@ async function bootstrap() {
whitelist: true
})
);

await app.listen(configService.get('HEIMDALL_SERVER_PORT') || 3000);
await app.listen(configService.get('PORT') || 3000);
}
bootstrap();
2 changes: 1 addition & 1 deletion apps/backend/test/.env-ci
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
HEIMDALL_SERVER_PORT=8000
PORT=8000
DATABASE_HOST=localhost
DATABASE_PORT=5432
DATABASE_PASSWORD=postgres
Expand Down
7 changes: 5 additions & 2 deletions apps/backend/test/constants/env-test.constant.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
export const ENV_MOCK_FILE =
'HEIMDALL_SERVER_PORT=8000\n' +
'PORT=8000\n' +
'DATABASE_HOST=localhost\n' +
'DATABASE_PORT=5432\n' +
'DATABASE_USERNAME=postgres\n' +
Expand All @@ -8,4 +8,7 @@ export const ENV_MOCK_FILE =
'JWT_SECRET=abc123\n' +
'NODE_ENV=test\n';

export const SIMPLE_ENV_MOCK_FILE = 'HEIMDALL_SERVER_PORT=8001\n';
export const SIMPLE_ENV_MOCK_FILE = 'PORT=8001\n';

export const DATABASE_URL_MOCK_ENV =
'DATABASE_URL=postgres://abcdefghijk123456:000011112222333344455556666777778889999aaaabbbbccccddddeeeffff@ec2-00-000-11-123.compute-1.amazonaws.com:5432/database01';
3 changes: 1 addition & 2 deletions apps/backend/test/integration/authentication.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,7 @@ describe('Authentication', () => {
databaseService = moduleFixture.get<DatabaseService>(DatabaseService);
configService = moduleFixture.get<ConfigService>(ConfigService);

appUrl = `http://localhost:${configService.get('HEIMDALL_SERVER_PORT') ||
'3000'}`;
appUrl = `http://localhost:${configService.get('PORT') || '3000'}`;

integrationSpecHelper = new IntegrationSpecHelper(appUrl);
});
Expand Down
3 changes: 1 addition & 2 deletions apps/backend/test/integration/registration.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,7 @@ describe('Registration', () => {
databaseService = moduleFixture.get<DatabaseService>(DatabaseService);
configService = moduleFixture.get<ConfigService>(ConfigService);

appUrl = `http://localhost:${configService.get('HEIMDALL_SERVER_PORT') ||
'3000'}`;
appUrl = `http://localhost:${configService.get('PORT') || '3000'}`;
});

beforeEach(async () => {
Expand Down
6 changes: 3 additions & 3 deletions apps/frontend/vue.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@ module.exports = {
devServer: {
// JWT_SECRET is a required secret for the backend. If it is sourced
// then it is safe to assume the app is in server mode in development.
// HEIMDALL_SERVER_PORT is not required so use the default backend port value
// is used here if JWT_SECRET is applied but HEIMDALL_SERVER_PORT is undefined
// PORT is not required so use the default backend port value
// is used here if JWT_SECRET is applied but PORT is undefined
proxy: process.env.JWT_SECRET
? 'http://127.0.0.1:' + (process.env.HEIMDALL_SERVER_PORT || 3000)
? `http://127.0.0.1:' + ${process.env.PORT || 3000}`
: ''
},
outputDir: '../../dist/frontend',
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
"frontend": "yarn workspace heimdall-lite",
"backend": "yarn workspace heimdall-server",
"build": "npx lerna run build",
"start": "yarn backend start",
"lint": "npx lerna run lint",
"lint:ci": "npx lerna run lint:ci",
"start:dev": "dotenv -e apps/backend/.env -- npx lerna exec yarn run start:dev --ignore @heimdall/interfaces"
Expand Down