Skip to content

Commit 97ce319

Browse files
CCM-15372_RefactoringContainerBuildFlow (#98)
* CCM-15372_RefactoringContainerBuildFlow * CCM-15372_RefactoringContainerBuildFlow * CCM-15372_Refactoring Container Build Flow * CCM-15372: Changes from Template MGMT * CCM-15372: Changes from Template MGMT * CCM-14307 Bumping Trivy --------- Co-authored-by: jamesthompson26-nhs <james.thompson26@nhs.net>
1 parent bd1389e commit 97ce319

47 files changed

Lines changed: 518 additions & 1327 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.tool-versions

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,9 @@ gitleaks 8.24.0
33
jq 1.6
44
nodejs 22.11.0
55
pre-commit 3.6.0
6-
terraform 1.10.1
7-
terraform-docs 0.19.0
8-
trivy 0.61.0
6+
terraform 1.14.3
7+
terraform-docs 0.21.0
8+
trivy 0.69.3
99
vale 3.6.0
1010
python 3.13.2
1111

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,22 +26,22 @@ Agents should look for a nested `AGENTS.md` in or near these areas before making
2626
The root `package.json` is the orchestration manifestgit co for this repo. It does not ship application code; it wires up shared dev tooling and delegates to workspace-level projects.
2727

2828
- Workspaces: Declares the set of npm workspaces (e.g. under `lambdas/`, `utils/`, `tests/`, `scripts/`). Agents should add a new workspace path here when introducing a new npm project.
29-
- Scripts: Provides top-level commands that fan out across workspaces using `--workspaces` (lint, typecheck, unit tests) and project-specific runners (e.g. `lambda-build`).
29+
- Scripts: Provides top-level commands that fan out across workspaces using `--workspaces` (lint, typecheck, unit tests) and project-specific runners (e.g. `build-archive`).
3030
- Dev tool dependencies: Centralises Jest, TypeScript, ESLint configurations and plugins to keep versions consistent across workspaces. Workspace projects should rely on these unless a local override is strictly needed.
3131
- Overrides/resolutions: Pins transitive dependencies (e.g. Jest/react-is) to avoid ecosystem conflicts. Agents must not remove overrides without verifying tests across all workspaces.
3232

3333
Agent guidance:
3434

3535
- Before adding or removing a workspace, update the root `workspaces` array and ensure CI scripts still succeed with `npm run lint`, `npm run typecheck`, and `npm run test:unit` at the repo root.
36-
- When adding repo-wide scripts, keep names consistent with existing patterns (e.g. `lint`, `lint:fix`, `typecheck`, `test:unit`, `lambda-build`) and prefer `--workspaces` fan-out.
36+
- When adding repo-wide scripts, keep names consistent with existing patterns (e.g. `lint`, `lint:fix`, `typecheck`, `test:unit`, `build-archive`) and prefer `--workspaces` fan-out.
3737
- Do not publish from the root. If adding a new workspace intended for publication, mark that workspace package as `private: false` and keep the root as private.
3838
- Validate changes by running the repo pre-commit hooks: `make githooks-run`.
3939

4040
Success criteria for changes affecting the root `package.json`:
4141

4242
- `npm run lint`, `npm run typecheck`, and `npm run test:unit` pass at the repo root.
4343
- Workspace discovery is correct (new projects appear under `npm run typecheck --workspaces`).
44-
- No regression in lambda build tooling (`npm run lambda-build`).
44+
- No regression in lambda build tooling (`npm run build-archive`).
4545

4646
## What Agents Can / Can’t Do
4747

containers/example-app/build.sh

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/bin/bash
2+
3+
set -euo pipefail
4+
5+
rm -rf dist
6+
7+
npx esbuild \
8+
--bundle \
9+
--minify \
10+
--sourcemap \
11+
--target=es2022 \
12+
--platform=node \
13+
--entry-names=[name] \
14+
--outdir=dist \
15+
src/server.ts
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
ARG BASE_IMAGE
2+
3+
FROM ${BASE_IMAGE}
4+
5+
WORKDIR /app
6+
7+
COPY dist/ .
8+
9+
EXPOSE 8080
10+
11+
CMD ["node", "server.js"]
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
import type { Config } from 'jest';
2+
3+
const config: Config = {
4+
preset: 'ts-jest',
5+
6+
// Automatically clear mock calls, instances, contexts and results before every test
7+
clearMocks: true,
8+
9+
// Indicates whether the coverage information should be collected while executing the test
10+
collectCoverage: true,
11+
12+
// The directory where Jest should output its coverage files
13+
coverageDirectory: './.reports/unit/coverage',
14+
15+
// Indicates which provider should be used to instrument code for coverage
16+
coverageProvider: 'babel',
17+
18+
coverageThreshold: {
19+
global: {
20+
branches: 0,
21+
functions: 100,
22+
lines: 90,
23+
statements: -10,
24+
},
25+
},
26+
27+
coveragePathIgnorePatterns: ['/__tests__/'],
28+
transform: { '^.+\\.ts$': 'ts-jest' },
29+
testPathIgnorePatterns: ['.build'],
30+
testMatch: ['**/?(*.)+(spec|test).[jt]s?(x)'],
31+
32+
// Use this configuration option to add custom reporters to Jest
33+
reporters: [
34+
'default',
35+
[
36+
'jest-html-reporter',
37+
{
38+
pageTitle: 'Test Report',
39+
outputPath: './.reports/unit/test-report.html',
40+
includeFailureMsg: true,
41+
},
42+
],
43+
],
44+
45+
// The test environment that will be used for testing
46+
testEnvironment: 'node',
47+
};
48+
49+
export default config;
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
{
2+
"devDependencies": {
3+
"@tsconfig/node22": "^22.0.2",
4+
"@types/jest": "^29.5.14",
5+
"@types/node": "^22.0.0",
6+
"jest": "^29.7.0",
7+
"jest-mock-extended": "^3.0.7",
8+
"typescript": "^5.8.2"
9+
},
10+
"name": "nhs-notify-admail-example-app",
11+
"private": true,
12+
"unused-scripts": {
13+
"build:archive": "rm -rf dist && npx esbuild --bundle --minify --sourcemap --target=es2020 --platform=node --loader:.node=file --entry-names=[name] --outdir=dist src/index.ts"
14+
},
15+
"scripts": {
16+
"build:container": "cd ../.. && make docker-build-and-push base_image=node:22-alpine dir=containers/example-app",
17+
"lint": "eslint .",
18+
"lint:fix": "eslint . --fix",
19+
"test:unit": "jest",
20+
"typecheck": "tsc --noEmit"
21+
},
22+
"version": "0.0.1"
23+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
import http from 'http';
2+
import { createRequestHandler, startServer } from '../server';
3+
4+
describe('example-app server', () => {
5+
describe('createRequestHandler', () => {
6+
it('returns a request handler function', () => {
7+
const handler = createRequestHandler();
8+
expect(typeof handler).toBe('function');
9+
});
10+
11+
it('responds with 200 status and JSON body', (done) => {
12+
const handler = createRequestHandler();
13+
const mockReq = {} as http.IncomingMessage;
14+
const mockRes = {
15+
writeHead: jest.fn(),
16+
end: jest.fn(),
17+
} as unknown as http.ServerResponse;
18+
19+
handler(mockReq, mockRes);
20+
21+
expect(mockRes.writeHead).toHaveBeenCalledWith(200, { 'Content-Type': 'application/json' });
22+
expect(mockRes.end).toHaveBeenCalledWith(JSON.stringify({ status: 'ok' }));
23+
done();
24+
});
25+
});
26+
27+
describe('startServer', () => {
28+
let server: http.Server;
29+
const port = 8888;
30+
31+
afterEach((done) => {
32+
if (server) {
33+
server.close(done);
34+
} else {
35+
done();
36+
}
37+
});
38+
39+
it('starts server on specified port and responds correctly', (done) => {
40+
server = startServer(port);
41+
42+
// Wait a bit for server to start
43+
setTimeout(() => {
44+
http.get(`http://localhost:${port}`, (res) => {
45+
expect(res.statusCode).toBe(200);
46+
expect(res.headers['content-type']).toBe('application/json');
47+
48+
let body = '';
49+
res.on('data', (chunk) => {
50+
body += chunk;
51+
});
52+
53+
res.on('end', () => {
54+
expect(JSON.parse(body)).toEqual({ status: 'ok' });
55+
done();
56+
});
57+
});
58+
}, 100);
59+
});
60+
});
61+
});
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// Placeholder HTTP server for AppRunner. Replace with real application code.
2+
import http from 'http';
3+
4+
export const createRequestHandler = () => {
5+
return (_req: http.IncomingMessage, res: http.ServerResponse) => {
6+
res.writeHead(200, { 'Content-Type': 'application/json' });
7+
res.end(JSON.stringify({ status: 'ok' }));
8+
};
9+
};
10+
11+
export const startServer = (port: number = Number(process.env.PORT ?? 8080)) => {
12+
const server = http.createServer(createRequestHandler());
13+
server.listen(port, () => {
14+
console.log(`Placeholder app listening on port ${port}`);
15+
});
16+
return server;
17+
};
18+
19+
/* istanbul ignore next */
20+
// Only start server on local/direct run
21+
if (require.main === module) {
22+
startServer();
23+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"extends": "@tsconfig/node22/tsconfig.json",
3+
"include": [
4+
"src/**/*",
5+
"jest.config.ts"
6+
]
7+
}

0 commit comments

Comments
 (0)