Skip to content

Commit 29b57c3

Browse files
author
Lasim
committed
feat: Implement version management by creating version.ts and updating Dockerfile, workflows, and banner to use dynamic versioning
1 parent 0b0208e commit 29b57c3

File tree

9 files changed

+90
-67
lines changed

9 files changed

+90
-67
lines changed

.github/workflows/backend-release-pr.yml

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,11 @@ jobs:
7070
TYPE_ARG: ${{ fromJSON('{"patch":"patch", "minor":"minor", "major":"major"}')[github.event.inputs.type] }}
7171
BETA_ARG: ${{ github.event.inputs.beta == 'true' && '--preRelease=beta' || '' }}
7272
run: npm run release -- $TYPE_ARG --ci --verbose --no-git.push --no-git.commit --no-git.tag --no-github $BETA_ARG
73+
- name: Update version.ts file
74+
working-directory: services/backend
75+
run: |
76+
node scripts/update-version.js
77+
git add src/config/version.ts
7378
- name: get-npm-version
7479
id: package-version
7580
uses: martinbeentjes/npm-get-version-action@main
@@ -138,8 +143,6 @@ jobs:
138143
- `linux/amd64` (Intel/AMD)
139144
- `linux/arm64` (Apple Silicon, AWS Graviton)
140145
141-
### Environment Variables
142-
The Docker image will include `DEPLOYSTACK_BACKEND_VERSION` environment variable set to the current version.
143146
144147
## Release notes:
145148
${{ steps.extract-release-notes.outputs.release_notes }}

.github/workflows/backend-release.yml

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,5 @@ jobs:
8686
tags: |
8787
deploystack/backend:latest
8888
deploystack/backend:v${{ steps.package-version.outputs.current-version }}
89-
build-args: |
90-
DEPLOYSTACK_BACKEND_VERSION=${{ steps.package-version.outputs.current-version }}
9189
cache-from: type=gha
92-
cache-to: type=gha,mode=max
90+
cache-to: type=gha,mode=max

services/backend/Dockerfile

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
# Production image
22
FROM node:23-alpine
33

4-
ARG DEPLOYSTACK_BACKEND_VERSION
54
WORKDIR /app
65

76
# Copy package files
@@ -22,8 +21,7 @@ RUN mkdir -p /app/data
2221

2322
# Create a default .env file
2423
RUN echo "NODE_ENV=production" > .env && \
25-
echo "PORT=3000" >> .env && \
26-
echo "DEPLOYSTACK_BACKEND_VERSION=${DEPLOYSTACK_BACKEND_VERSION:-$(node -e "console.log(require('./package.json').version)")}" >> .env
24+
echo "PORT=3000" >> .env
2725

2826
EXPOSE 3000
2927
CMD ["node", "--env-file=.env", "dist/index.js"]
Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
const fs = require('fs');
2+
const path = require('path');
3+
4+
const packageJson = require('../package.json');
5+
const versionInfo = {
6+
version: packageJson.version,
7+
buildTime: new Date().toISOString(),
8+
source: 'release'
9+
};
10+
11+
// Read the current version.ts file
12+
const versionTsPath = path.join(__dirname, '../src/config/version.ts');
13+
let versionTsContent = fs.readFileSync(versionTsPath, 'utf8');
14+
15+
// Replace the versionData object
16+
const newVersionData = `let versionData: VersionInfo = {
17+
version: '${versionInfo.version}',
18+
buildTime: '${versionInfo.buildTime}',
19+
source: '${versionInfo.source}'
20+
};`;
21+
22+
// Use regex to replace the versionData assignment
23+
versionTsContent = versionTsContent.replace(
24+
/let versionData: VersionInfo = \{[\s\S]*?\};/,
25+
newVersionData
26+
);
27+
28+
// Write the updated file
29+
fs.writeFileSync(versionTsPath, versionTsContent);
30+
console.log(`Updated version.ts to version ${versionInfo.version}`);
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import * as fs from 'fs';
2+
import * as path from 'path';
3+
4+
export interface VersionInfo {
5+
version: string;
6+
buildTime: string;
7+
source: string;
8+
}
9+
10+
// This will be replaced by the build script
11+
let versionData: VersionInfo = {
12+
version: '0.20.9',
13+
buildTime: '2025-07-06T12:20:18.828Z',
14+
source: 'release'
15+
};
16+
17+
// Try to read from package.json as fallback for development
18+
try {
19+
const packageJsonPath = path.join(__dirname, '../../package.json');
20+
if (fs.existsSync(packageJsonPath)) {
21+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8'));
22+
versionData = {
23+
version: packageJson.version || '0.1.0',
24+
buildTime: new Date().toISOString(),
25+
source: 'package.json'
26+
};
27+
}
28+
} catch (error) {
29+
// Use static fallback if package.json can't be read
30+
}
31+
32+
export const getBackendVersion = (): VersionInfo => {
33+
return {
34+
version: versionData.version || '0.1.0',
35+
buildTime: versionData.buildTime,
36+
source: versionData.source
37+
};
38+
};
39+
40+
export const getVersionString = (): string => {
41+
return getBackendVersion().version;
42+
};

services/backend/src/routes/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { type FastifyInstance } from 'fastify'
22
import { z } from 'zod'
33
import { zodToJsonSchema } from 'zod-to-json-schema'
4+
import { getVersionString } from '../config/version'
45
// Import the individual database setup routes
56
import dbStatusRoute from './db/status'
67
import dbSetupRoute from './db/setup'
@@ -67,7 +68,7 @@ export const registerRoutes = (server: FastifyInstance): void => {
6768
message: 'DeployStack Backend is running.',
6869
status: server.db ? 'Database Connected' : 'Database Not Configured/Connected - Use /api/db/status and /api/db/setup',
6970
timestamp: new Date().toISOString(),
70-
version: '0.20.9'
71+
version: getVersionString()
7172
}
7273
})
7374
}

services/backend/src/utils/banner.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
import type { FastifyBaseLogger } from 'fastify';
2+
import { getVersionString } from '../config/version';
23

34
// Function to display fancy startup banner
45
export const displayStartupBanner = (port: number, logger: FastifyBaseLogger): void => {
5-
const version = process.env.DEPLOYSTACK_BACKEND_VERSION || process.env.npm_package_version || '0.1.0';
6+
const version = getVersionString();
67

78
const message = `
89
\x1b[38;5;51m╔═══════════════════════════════════════════════════════════════════════════════════════════════

services/backend/tests/unit/utils/banner.test.ts

Lines changed: 6 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -90,43 +90,16 @@ describe('banner.ts', () => {
9090
expect(bannerOutput).toContain('\x1b[0m'); // Reset color
9191
});
9292

93-
it('should use DEPLOYSTACK_BACKEND_VERSION when available', () => {
94-
process.env.DEPLOYSTACK_BACKEND_VERSION = '1.2.3';
93+
it('should use version from config', () => {
9594
const testPort = 3000;
9695

9796
displayStartupBanner(testPort, mockLogger);
9897

9998
const logCall = (mockLogger.info as any).mock.calls[0];
10099
const bannerOutput = logCall[1] as string;
101-
expect(bannerOutput).toContain('v1.2.3');
102-
expect(bannerOutput).toContain('DeployStack CI/CD Backend');
103-
expect(logCall[0].version).toBe('1.2.3');
104-
});
105-
106-
it('should fallback to npm_package_version when DEPLOYSTACK_BACKEND_VERSION is not set', () => {
107-
delete process.env.DEPLOYSTACK_BACKEND_VERSION;
108-
process.env.npm_package_version = '2.1.0';
109-
const testPort = 3000;
110-
111-
displayStartupBanner(testPort, mockLogger);
112-
113-
const logCall = (mockLogger.info as any).mock.calls[0];
114-
const bannerOutput = logCall[1] as string;
115-
expect(bannerOutput).toContain('v2.1.0');
116-
expect(logCall[0].version).toBe('2.1.0');
117-
});
118-
119-
it('should use default version when no version environment variables are set', () => {
120-
delete process.env.DEPLOYSTACK_BACKEND_VERSION;
121-
delete process.env.npm_package_version;
122-
const testPort = 3000;
123-
124-
displayStartupBanner(testPort, mockLogger);
125-
126-
const logCall = (mockLogger.info as any).mock.calls[0];
127-
const bannerOutput = logCall[1] as string;
128-
expect(bannerOutput).toContain('v0.1.0');
129-
expect(logCall[0].version).toBe('0.1.0');
100+
// Should use the version from version.ts (which reads from package.json in development)
101+
expect(bannerOutput).toContain('v0.20.9');
102+
expect(logCall[0].version).toBe('0.20.9');
130103
});
131104

132105
it('should display current NODE_ENV', () => {
@@ -249,11 +222,7 @@ describe('banner.ts', () => {
249222

250223
it('should handle empty string environment variables gracefully', () => {
251224
const originalNodeEnv = process.env.NODE_ENV;
252-
const originalBackendVersion = process.env.DEPLOYSTACK_BACKEND_VERSION;
253-
const originalNpmVersion = process.env.npm_package_version;
254225

255-
process.env.DEPLOYSTACK_BACKEND_VERSION = '';
256-
process.env.npm_package_version = '';
257226
process.env.NODE_ENV = '';
258227
const testPort = 3000;
259228

@@ -262,35 +231,15 @@ describe('banner.ts', () => {
262231
const logCall = (mockLogger.info as any).mock.calls[0];
263232
const bannerOutput = logCall[1] as string;
264233
const cleanOutput = stripAnsiCodes(bannerOutput);
265-
expect(cleanOutput).toContain('v0.1.0'); // Should fallback to default
234+
expect(cleanOutput).toContain('v0.20.9'); // Should use version.ts data
266235
expect(cleanOutput).toContain('Environment: development'); // Should fallback to default
267-
expect(logCall[0].version).toBe('0.1.0');
236+
expect(logCall[0].version).toBe('0.20.9');
268237
expect(logCall[0].environment).toBe('development');
269238

270239
// Restore original environment variables
271240
if (originalNodeEnv !== undefined) {
272241
process.env.NODE_ENV = originalNodeEnv;
273242
}
274-
if (originalBackendVersion !== undefined) {
275-
process.env.DEPLOYSTACK_BACKEND_VERSION = originalBackendVersion;
276-
}
277-
if (originalNpmVersion !== undefined) {
278-
process.env.npm_package_version = originalNpmVersion;
279-
}
280-
});
281-
282-
it('should prioritize DEPLOYSTACK_BACKEND_VERSION over npm_package_version', () => {
283-
process.env.DEPLOYSTACK_BACKEND_VERSION = '5.0.0';
284-
process.env.npm_package_version = '4.0.0';
285-
const testPort = 3000;
286-
287-
displayStartupBanner(testPort, mockLogger);
288-
289-
const logCall = (mockLogger.info as any).mock.calls[0];
290-
const bannerOutput = logCall[1] as string;
291-
expect(bannerOutput).toContain('v5.0.0');
292-
expect(bannerOutput).not.toContain('v4.0.0');
293-
expect(logCall[0].version).toBe('5.0.0');
294243
});
295244
});
296245
});

services/backend/tsconfig.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"strict": true,
88
"skipLibCheck": true,
99
"esModuleInterop": true,
10+
"resolveJsonModule": true,
1011
"baseUrl": ".",
1112
"paths": {
1213
"@src/*": ["src/*"]

0 commit comments

Comments
 (0)