Skip to content

Commit

Permalink
Merge branch 'main' into Nomenclature-for-Developer-Estimates-plus-Fo…
Browse files Browse the repository at this point in the history
…rm-behavior
  • Loading branch information
austenstone committed Dec 3, 2024
2 parents 71497fd + 2726233 commit 9fbfe6b
Show file tree
Hide file tree
Showing 102 changed files with 3,576 additions and 2,730 deletions.
2 changes: 1 addition & 1 deletion .vscode/launch.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
"request": "launch",
"name": "Debug Backend",
"type": "node",
"program": "${workspaceFolder}/backend/src/app.ts",
"program": "${workspaceFolder}/backend/src/index.ts",
"preLaunchTask": "npm: build - backend",
"cwd": "${workspaceFolder}/backend",
"envFile": "${workspaceFolder}/backend/.env",
Expand Down
4 changes: 2 additions & 2 deletions .vscode/tasks.json
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@
"isBackground": true,
"problemMatcher": [],
"label": "npm: dev - backend with db",
"detail": "tsx src/app.ts | bunyan -o short",
"detail": "tsx src/index.ts | bunyan -o short",
"icon": {
"id": "server"
},
Expand All @@ -132,7 +132,7 @@
"script": "start",
"path": "backend",
"label": "npm: start - backend",
"detail": "node dist/app.js | bunyan -o short",
"detail": "node dist/index.js | bunyan -o short",
"icon": {
"id": "server"
},
Expand Down
2 changes: 1 addition & 1 deletion Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ WORKDIR /app/backend

EXPOSE 80

CMD node dist/app.js | ./node_modules/.bin/bunyan
CMD node dist/index.js | ./node_modules/.bin/bunyan
47 changes: 0 additions & 47 deletions backend/__tests__/survey.test.ts

This file was deleted.

15 changes: 14 additions & 1 deletion backend/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 5 additions & 4 deletions backend/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@
"version": "1.0.0",
"description": "Demonstrate the value of GitHub",
"type": "module",
"main": "src/app.ts",
"main": "src/index.ts",
"scripts": {
"start": "node --enable-source-maps dist/app.js",
"start": "node --enable-source-maps dist/index.js | bunyan -o short -l info",
"test": "jest",
"build": "tsc",
"dev": "tsx watch src/app.ts | bunyan -o short -l debug",
"dev": "tsx watch src/index.ts | bunyan -o short -l debug",
"lint": "eslint src/**/*.ts",
"db:start": "docker-compose -f ../compose.yml up -d db",
"dotenv": "cp -n .env.example .env || true"
Expand All @@ -25,7 +25,8 @@
"octokit": "^4.0.2",
"sequelize": "^6.37.5",
"smee-client": "^2.0.4",
"update-dotenv": "^1.1.1"
"update-dotenv": "^1.1.1",
"why-is-node-running": "^3.2.1"
},
"devDependencies": {
"@eslint/js": "^9.14.0",
Expand Down
201 changes: 152 additions & 49 deletions backend/src/app.ts
Original file line number Diff line number Diff line change
@@ -1,59 +1,162 @@
import 'dotenv/config'
import express from 'express';
import express, { Express } from 'express';
import rateLimit from 'express-rate-limit';
import bodyParser from 'body-parser';
import cors from 'cors';
import path, { dirname } from 'path';
import apiRoutes from "./routes/index.js"
import { dbConnect } from './database.js';
import setup from './services/setup.js';
import settingsService from './services/settings.service.js';
import SmeeService from './services/smee.js';
import logger, { expressLoggerMiddleware } from './services/logger.js';
import { fileURLToPath } from 'url';
import * as http from 'http';
import Database from './database.js';
import logger, { expressLoggerMiddleware } from './services/logger.js';
import GitHub from './github.js';
import SettingsService from './services/settings.service.js';
import apiRoutes from "./routes/index.js"
import WebhookService from './services/smee.js';

class App {
e: Express;
eListener?: http.Server;
baseUrl?: string;
public database: Database;
public github: GitHub;
public settingsService: SettingsService;

const PORT = Number(process.env.PORT) || 80;

export const app = express();
app.use(cors());
app.use(expressLoggerMiddleware);

(async () => {
await dbConnect();
logger.info('DB Connected ✅');
await settingsService.initializeSettings();
logger.info('Settings loaded ✅');
await SmeeService.createSmeeWebhookProxy(PORT);
logger.info('Created Smee webhook proxy ✅');

try {
await setup.createAppFromEnv();
logger.info('Created GitHub App from environment ✅');
} catch (error) {
logger.info('Failed to create app from environment. This is expected if the app is not yet installed.', error);
constructor(
public port: number
) {
this.baseUrl = process.env.BASE_URL || 'http://localhost:' + port;
this.e = express();
this.port = port;
this.database = new Database(process.env.JAWSDB_URL ? process.env.JAWSDB_URL : {
host: process.env.MYSQL_HOST,
port: Number(process.env.MYSQL_PORT) || 3306,
username: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE || 'value'
});
const webhookService = new WebhookService({
url: process.env.WEBHOOK_PROXY_URL,
path: '/api/github/webhooks',
port
});
this.github = new GitHub(
{
appId: process.env.GITHUB_APP_ID,
privateKey: process.env.GITHUB_APP_PRIVATE_KEY,
webhooks: {
secret: process.env.GITHUB_WEBHOOK_SECRET
}
},
this.e,
webhookService,
this.baseUrl
)
this.settingsService = new SettingsService({
baseUrl: this.baseUrl,
webhookProxyUrl: process.env.GITHUB_WEBHOOK_PROXY_URL,
webhookSecret: process.env.GITHUB_WEBHOOK_SECRET,
metricsCronExpression: '0 0 * * *',
devCostPerYear: '100000',
developerCount: '100',
hoursPerYear: '2080',
percentTimeSaved: '20',
percentCoding: '20'
})
}

app.use((req, res, next) => {
if (req.path === '/api/github/webhooks') {
return next();
}
bodyParser.json()(req, res, next);
}, bodyParser.urlencoded({ extended: true }));
app.use('/api', apiRoutes);

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const frontendPath = path.resolve(__dirname, '../../frontend/dist/github-value/browser');

app.use(express.static(frontendPath));
app.get('*', rateLimit({
windowMs: 15 * 60 * 1000, max: 5000,
}), (_, res) => res.sendFile(path.join(frontendPath, 'index.html')));

app.listen(PORT, () => {
logger.info(`Server is running at http://localhost:${PORT} 🚀`);
if (process.env.WEB_URL) {
logger.debug(`Frontend is running at ${process.env.WEB_URL} 🚀`);
public async start() {
try {
logger.info('Starting application');

logger.info('Express setup...');
this.setupExpress();
logger.info('Express setup complete');

logger.info('Database connecting...');
await this.database.connect();
logger.info('Database connected');

logger.info('Initializing settings...');
await this.initializeSettings();
logger.info('Settings initialized');

logger.info('GitHub App starting...');
await this.github.connect();
logger.info('GitHub App connected');

return this.e;
} catch (error) {
await this.github.smee.connect();
logger.error('Failed to start application ❌');
if (error instanceof Error) {
logger.error(error.message);
}
logger.debug(error);
}
});
})();
}

public async stop() {
await new Promise(resolve => this.eListener?.close(resolve));
await this.database.disconnect();
await this.github.disconnect();
}

private setupExpress() {
this.e.use(cors());
this.e.use(expressLoggerMiddleware);
this.e.use((req, res, next) => {
if (req.path === '/api/github/webhooks') {
return next();
}
bodyParser.json()(req, res, next);
}, bodyParser.urlencoded({ extended: true }));

this.e.use('/api', apiRoutes);

const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const frontendPath = path.resolve(__dirname, '../../frontend/dist/github-value/browser');
this.e.use(express.static(frontendPath));
this.e.get(
'*',
rateLimit({
windowMs: 15 * 60 * 1000, max: 5000,
}),
(_, res) => res.sendFile(path.join(frontendPath, 'index.html'))
);

this.eListener = this.e.listen(this.port);
}

private initializeSettings() {
this.settingsService.initialize()
.then(async (settings) => {
if (settings.webhookProxyUrl) {
this.github.smee.options.url = settings.webhookProxyUrl
}
if (settings.webhookSecret) {
this.github.setInput({
webhooks: {
secret: settings.webhookSecret
}
});
}
if (settings.metricsCronExpression) {
this.github.cronExpression = settings.metricsCronExpression;
}
if (settings.baseUrl) {
this.baseUrl = settings.baseUrl;
}
})
.finally(async () => {
await this.github.smee.connect()
await this.settingsService.updateSetting('webhookSecret', this.github.input.webhooks?.secret || '');
await this.settingsService.updateSetting('webhookProxyUrl', this.github.smee.options.url!);
await this.settingsService.updateSetting('metricsCronExpression', this.github.cronExpression!);
});
}
}

export {
App as default
};
4 changes: 2 additions & 2 deletions backend/src/controllers/metrics.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import MetricsService from '../services/metrics.service.js';
class MetricsController {
async getMetrics(req: Request, res: Response): Promise<void> {
try {
const metrics = await MetricsService.queryMetrics(req.query)
const metrics = await MetricsService.getMetrics(req.query)
res.status(200).json(metrics);
} catch (error) {
res.status(500).json(error);
Expand All @@ -13,7 +13,7 @@ class MetricsController {

async getMetricsTotals(req: Request, res: Response): Promise<void> {
try {
const metrics = await MetricsService.queryMetricsTotals(req.query)
const metrics = await MetricsService.getMetricsTotals(req.query)
res.status(200).json(metrics);
} catch (error) {
res.status(500).json(error);
Expand Down
Loading

0 comments on commit 9fbfe6b

Please sign in to comment.