@abgov/nx-oc 12.4.0 → 12.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,13 +1,148 @@
1
- # About this project
2
- This is the Government of Alberta - Nx plugin for OpenShift.
1
+ # @abgov/nx-oc
3
2
 
4
- The plugin includes generators for setting up OpenShift pipeline and application yaml files, and executors for `oc cli` commands.
3
+ Nx plugin for generating and applying OpenShift manifests for Government of Alberta applications.
5
4
 
6
- ## TLDR
5
+ The plugin provides generators for CI/CD pipeline setup and per-application deployment configuration, and an executor for running `oc apply` against an OpenShift cluster.
7
6
 
8
- 1. Create your Nx workspace using `npx create-nx-workspace my-workspace`
9
- 2. Install plugin: `npm i -D @abgov/nx-oc`
10
- 3. Login to OpenShift: `oc login {url} --token={token}`
11
- 4. Generate basic infrastructure yml and apply it: `npx nx g @abgov/nx-oc:pipeline`
12
- 5. Set up OpenShift yml on apps using `npx nx g @abgov/nx-oc:deployment`
7
+ ## Prerequisites
13
8
 
9
+ - [OpenShift CLI (`oc`)](https://docs.openshift.com/container-platform/latest/cli_reference/openshift_cli/getting-started-cli.html) installed and on `PATH`
10
+ - An active OpenShift login: `oc login <url> --token=<token>`
11
+ - Separate OpenShift projects provisioned for build infrastructure and each runtime environment (dev, test, prod)
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm i -D @abgov/nx-oc
17
+ ```
18
+
19
+ ## Quick Start
20
+
21
+ ```bash
22
+ # 1. Create workspace and install plugin
23
+ npx create-nx-workspace my-workspace
24
+ npm i -D @abgov/nx-oc
25
+
26
+ # 2. Login to OpenShift
27
+ oc login <url> --token=<token>
28
+
29
+ # 3. Generate pipeline infrastructure manifests
30
+ npx nx g @abgov/nx-oc:pipeline my-pipeline \
31
+ --infra my-infra-project \
32
+ --envs "my-dev my-test my-prod" \
33
+ --registry ghcr.io/my-org
34
+
35
+ # 4. Apply the generated infrastructure manifests to the cluster
36
+ npx nx g @abgov/nx-oc:apply-infra
37
+
38
+ # 5. Add deployment manifests to each application
39
+ npx nx g @abgov/nx-oc:deployment my-app --appType node --env dev
40
+ ```
41
+
42
+ ## Generators
43
+
44
+ ### `pipeline`
45
+
46
+ Generates OpenShift manifests for a CI/CD pipeline, including shared build infrastructure resources used across all environments.
47
+
48
+ ```bash
49
+ npx nx g @abgov/nx-oc:pipeline my-pipeline \
50
+ --infra my-infra-project \
51
+ --envs "my-dev my-test my-prod" \
52
+ --registry ghcr.io/my-org \
53
+ --type actions
54
+ ```
55
+
56
+ | Option | Alias | Required | Description |
57
+ |--------|-------|----------|-------------|
58
+ | `pipeline` | — | Yes | Name of the OpenShift pipeline |
59
+ | `infra` | `-i` | Yes | OpenShift project name used for build infrastructure |
60
+ | `envs` | `-e` | Yes | Space-separated names of the OpenShift environment projects (e.g., `"my-dev my-test my-prod"`) |
61
+ | `registry` | `-r` | Yes | Container registry to publish images to (e.g., `ghcr.io/my-org`) |
62
+ | `type` | `-t` | No | Pipeline type: `actions` (default) or `jenkins` |
63
+ | `apply` | `-a` | No | Apply the generated manifests to OpenShift immediately after generation |
64
+
65
+ ---
66
+
67
+ ### `apply-infra`
68
+
69
+ Applies the OpenShift infrastructure manifests that were generated by `pipeline`. Takes no options — reads the generated pipeline configuration from the workspace.
70
+
71
+ ```bash
72
+ npx nx g @abgov/nx-oc:apply-infra
73
+ ```
74
+
75
+ Use `apply-infra` as a follow-up to `pipeline` when you want to defer cluster provisioning, or as a re-apply step after editing the generated manifests.
76
+
77
+ ---
78
+
79
+ ### `deployment`
80
+
81
+ Adds OpenShift deployment manifests (Deployment, Service, Route, etc.) to an existing Nx project for a specific environment.
82
+
83
+ ```bash
84
+ npx nx g @abgov/nx-oc:deployment my-app --appType node --env dev
85
+ ```
86
+
87
+ | Option | Alias | Required | Description |
88
+ |--------|-------|----------|-------------|
89
+ | `project` | — | Yes | Name of the existing Nx project to add deployment manifests to |
90
+ | `appType` | `-t` | Yes | Application type: `frontend`, `dotnet`, or `node` |
91
+ | `env` | `-e` | Yes | ADSP environment: `dev`, `test`, or `prod` |
92
+ | `accessToken` | `-at` | No | Access token for non-interactive retrieval of ADSP configuration |
93
+
94
+ Run the generator once per environment per application. For a typical three-environment setup, run it three times with `--env dev`, `--env test`, and `--env prod`.
95
+
96
+ ---
97
+
98
+ ## Executor: `apply`
99
+
100
+ Runs `oc apply` to deploy an application's OpenShift manifests. Configure it as a target in the project's `project.json`:
101
+
102
+ ```json
103
+ {
104
+ "targets": {
105
+ "deploy": {
106
+ "executor": "@abgov/nx-oc:apply",
107
+ "options": {
108
+ "ocProject": "my-dev-project"
109
+ }
110
+ }
111
+ }
112
+ }
113
+ ```
114
+
115
+ Then run:
116
+
117
+ ```bash
118
+ npx nx run my-app:deploy
119
+ ```
120
+
121
+ ### Options
122
+
123
+ | Option | Required | Description |
124
+ |--------|----------|-------------|
125
+ | `ocProject` | Yes | OpenShift project(s) to apply manifests to |
126
+
127
+ `ocProject` accepts three forms:
128
+
129
+ ```json
130
+ // Single project
131
+ { "ocProject": "my-dev" }
132
+
133
+ // Multiple projects
134
+ { "ocProject": ["my-dev", "my-test"] }
135
+
136
+ // Tagged deployments
137
+ { "ocProject": [{ "project": "my-dev", "tag": "v1.2.3" }] }
138
+ ```
139
+
140
+ ---
141
+
142
+ ## Typical workflow
143
+
144
+ 1. Run `pipeline` once per workspace to generate shared build infrastructure manifests.
145
+ 2. Run `apply-infra` (or pass `--apply` to `pipeline`) to provision the resources on the cluster.
146
+ 3. Run `deployment` for each application and environment combination.
147
+ 4. Add an `apply` executor target to each application's `project.json`.
148
+ 5. In your GitHub Actions or Jenkins pipeline, call `npx nx run my-app:deploy` to apply manifests during CI/CD.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/nx-oc",
3
- "version": "12.4.0",
3
+ "version": "12.6.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "src/index.js",
6
6
  "description": "Government of Alberta - Nx plugin for OpenShift.",
@@ -14,12 +14,14 @@ const express = require("express");
14
14
  const open = require("open");
15
15
  const simple_oauth2_1 = require("simple-oauth2");
16
16
  const environments_1 = require("./environments");
17
+ const token_cache_1 = require("./token-cache");
17
18
  function hasDependency(host, dependency) {
18
19
  const { dependencies, devDependencies } = (0, devkit_1.readJson)(host, 'package.json');
19
20
  return !!(dependencies === null || dependencies === void 0 ? void 0 : dependencies[dependency]) || !!(devDependencies === null || devDependencies === void 0 ? void 0 : devDependencies[dependency]);
20
21
  }
21
22
  function realmLogin(accessServiceUrl, realm) {
22
23
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
24
+ var _a, _b;
23
25
  const client = new simple_oauth2_1.AuthorizationCode({
24
26
  client: {
25
27
  id: 'nx-adsp-cli',
@@ -31,6 +33,28 @@ function realmLogin(accessServiceUrl, realm) {
31
33
  authorizePath: `/auth/realms/${realm}/protocol/openid-connect/auth`,
32
34
  },
33
35
  });
36
+ // Core realm is only used to fetch the tenant list — not worth caching.
37
+ if (realm !== 'core') {
38
+ const cached = (0, token_cache_1.getCachedToken)(accessServiceUrl, realm);
39
+ if (cached) {
40
+ if (!(0, token_cache_1.isExpired)(cached)) {
41
+ return cached.accessToken;
42
+ }
43
+ if (cached.refreshToken) {
44
+ try {
45
+ const { token } = yield client
46
+ .createToken({ access_token: cached.accessToken, refresh_token: cached.refreshToken })
47
+ .refresh();
48
+ const expiresIn = (_a = token['expires_in']) !== null && _a !== void 0 ? _a : 300;
49
+ (0, token_cache_1.setCachedToken)(accessServiceUrl, realm, token['access_token'], token['refresh_token'], expiresIn);
50
+ return token['access_token'];
51
+ }
52
+ catch (_c) {
53
+ // Refresh failed — fall through to browser login.
54
+ }
55
+ }
56
+ }
57
+ }
34
58
  const redirect_uri = 'http://localhost:3000/callback';
35
59
  const authorizationUri = client.authorizeURL({
36
60
  redirect_uri,
@@ -59,6 +83,10 @@ function realmLogin(accessServiceUrl, realm) {
59
83
  tokenPromise,
60
84
  new Promise((_, reject) => setTimeout(() => reject(new Error('Timed out waiting for login.')), 120000)),
61
85
  ]).finally(() => server.close());
86
+ if (realm !== 'core') {
87
+ const expiresIn = (_b = token['expires_in']) !== null && _b !== void 0 ? _b : 300;
88
+ (0, token_cache_1.setCachedToken)(accessServiceUrl, realm, token['access_token'], token['refresh_token'], expiresIn);
89
+ }
62
90
  return token['access_token'];
63
91
  });
64
92
  }
@@ -1 +1 @@
1
- {"version":3,"file":"adsp-utils.js","sourceRoot":"","sources":["../../../../../packages/nx-oc/src/adsp/adsp-utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"adsp-utils.js","sourceRoot":"","sources":["../../../../../packages/nx-oc/src/adsp/adsp-utils.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,9 @@
1
+ export interface CacheEntry {
2
+ accessToken: string;
3
+ refreshToken?: string;
4
+ expiresAt: string;
5
+ }
6
+ export declare function getCacheFilePath(): string;
7
+ export declare function isExpired(entry: CacheEntry): boolean;
8
+ export declare function getCachedToken(accessServiceUrl: string, realm: string): CacheEntry | null;
9
+ export declare function setCachedToken(accessServiceUrl: string, realm: string, accessToken: string, refreshToken: string | undefined, expiresIn: number): void;
@@ -0,0 +1,49 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getCacheFilePath = getCacheFilePath;
4
+ exports.isExpired = isExpired;
5
+ exports.getCachedToken = getCachedToken;
6
+ exports.setCachedToken = setCachedToken;
7
+ const fs = require("fs");
8
+ const os = require("os");
9
+ const path = require("path");
10
+ const EXPIRY_BUFFER_MS = 60000;
11
+ function getCacheFilePath() {
12
+ return path.join(os.homedir(), '.nx-adsp', 'token-cache.json');
13
+ }
14
+ function readCache() {
15
+ try {
16
+ return JSON.parse(fs.readFileSync(getCacheFilePath(), 'utf-8'));
17
+ }
18
+ catch (_a) {
19
+ return {};
20
+ }
21
+ }
22
+ function writeCache(cache) {
23
+ const filePath = getCacheFilePath();
24
+ const dir = path.dirname(filePath);
25
+ if (!fs.existsSync(dir)) {
26
+ fs.mkdirSync(dir, { recursive: true, mode: 0o700 });
27
+ }
28
+ fs.writeFileSync(filePath, JSON.stringify(cache, null, 2), { mode: 0o600, encoding: 'utf-8' });
29
+ }
30
+ function cacheKey(accessServiceUrl, realm) {
31
+ return `${accessServiceUrl}::${realm}`;
32
+ }
33
+ function isExpired(entry) {
34
+ return new Date(entry.expiresAt).getTime() - EXPIRY_BUFFER_MS < Date.now();
35
+ }
36
+ function getCachedToken(accessServiceUrl, realm) {
37
+ var _a;
38
+ return (_a = readCache()[cacheKey(accessServiceUrl, realm)]) !== null && _a !== void 0 ? _a : null;
39
+ }
40
+ function setCachedToken(accessServiceUrl, realm, accessToken, refreshToken, expiresIn) {
41
+ const cache = readCache();
42
+ cache[cacheKey(accessServiceUrl, realm)] = {
43
+ accessToken,
44
+ refreshToken,
45
+ expiresAt: new Date(Date.now() + expiresIn * 1000).toISOString(),
46
+ };
47
+ writeCache(cache);
48
+ }
49
+ //# sourceMappingURL=token-cache.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"token-cache.js","sourceRoot":"","sources":["../../../../../packages/nx-oc/src/adsp/token-cache.ts"],"names":[],"mappings":";;AAcA,4CAEC;AAuBD,8BAEC;AAED,wCAEC;AAED,wCAcC;AA7DD,yBAAyB;AACzB,yBAAyB;AACzB,6BAA6B;AAU7B,MAAM,gBAAgB,GAAG,KAAM,CAAC;AAEhC,SAAgB,gBAAgB;IAC9B,OAAO,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,UAAU,EAAE,kBAAkB,CAAC,CAAC;AACjE,CAAC;AAED,SAAS,SAAS;IAChB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,gBAAgB,EAAE,EAAE,OAAO,CAAC,CAAe,CAAC;IAChF,CAAC;IAAC,WAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAiB;IACnC,MAAM,QAAQ,GAAG,gBAAgB,EAAE,CAAC;IACpC,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACnC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;QACxB,EAAE,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACtD,CAAC;IACD,EAAE,CAAC,aAAa,CAAC,QAAQ,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;AACjG,CAAC;AAED,SAAS,QAAQ,CAAC,gBAAwB,EAAE,KAAa;IACvD,OAAO,GAAG,gBAAgB,KAAK,KAAK,EAAE,CAAC;AACzC,CAAC;AAED,SAAgB,SAAS,CAAC,KAAiB;IACzC,OAAO,IAAI,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,gBAAgB,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;AAC7E,CAAC;AAED,SAAgB,cAAc,CAAC,gBAAwB,EAAE,KAAa;;IACpE,OAAO,MAAA,SAAS,EAAE,CAAC,QAAQ,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC,mCAAI,IAAI,CAAC;AAChE,CAAC;AAED,SAAgB,cAAc,CAC5B,gBAAwB,EACxB,KAAa,EACb,WAAmB,EACnB,YAAgC,EAChC,SAAiB;IAEjB,MAAM,KAAK,GAAG,SAAS,EAAE,CAAC;IAC1B,KAAK,CAAC,QAAQ,CAAC,gBAAgB,EAAE,KAAK,CAAC,CAAC,GAAG;QACzC,WAAW;QACX,YAAY;QACZ,SAAS,EAAE,IAAI,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;KACjE,CAAC;IACF,UAAU,CAAC,KAAK,CAAC,CAAC;AACpB,CAAC"}
@@ -0,0 +1,117 @@
1
+ import * as fs from 'fs';
2
+ import * as os from 'os';
3
+ import * as path from 'path';
4
+ import { getCacheFilePath, getCachedToken, isExpired, setCachedToken, CacheEntry } from './token-cache';
5
+
6
+ jest.mock('fs');
7
+ jest.mock('os');
8
+
9
+ const mockedFs = jest.mocked(fs);
10
+ const mockedOs = jest.mocked(os);
11
+
12
+ const FAKE_HOME = '/home/testuser';
13
+ const CACHE_PATH = path.join(FAKE_HOME, '.nx-adsp', 'token-cache.json');
14
+
15
+ const ACCESS_URL = 'https://access.example.com/auth';
16
+ const REALM = 'my-tenant';
17
+
18
+ function futureIso(secondsFromNow: number): string {
19
+ return new Date(Date.now() + secondsFromNow * 1000).toISOString();
20
+ }
21
+
22
+ function pastIso(secondsAgo: number): string {
23
+ return new Date(Date.now() - secondsAgo * 1000).toISOString();
24
+ }
25
+
26
+ describe('getCacheFilePath', () => {
27
+ it('returns path under home directory', () => {
28
+ mockedOs.homedir.mockReturnValue(FAKE_HOME);
29
+ expect(getCacheFilePath()).toBe(CACHE_PATH);
30
+ });
31
+ });
32
+
33
+ describe('isExpired', () => {
34
+ it('returns false when token expires in the future (beyond buffer)', () => {
35
+ const entry: CacheEntry = { accessToken: 'tok', expiresAt: futureIso(120) };
36
+ expect(isExpired(entry)).toBe(false);
37
+ });
38
+
39
+ it('returns true when token is past its expiry', () => {
40
+ const entry: CacheEntry = { accessToken: 'tok', expiresAt: pastIso(10) };
41
+ expect(isExpired(entry)).toBe(true);
42
+ });
43
+
44
+ it('returns true when token expires within the 60-second buffer', () => {
45
+ const entry: CacheEntry = { accessToken: 'tok', expiresAt: futureIso(30) };
46
+ expect(isExpired(entry)).toBe(true);
47
+ });
48
+ });
49
+
50
+ describe('getCachedToken', () => {
51
+ beforeEach(() => {
52
+ mockedOs.homedir.mockReturnValue(FAKE_HOME);
53
+ });
54
+
55
+ it('returns null when cache file does not exist', () => {
56
+ mockedFs.readFileSync.mockImplementation(() => { throw new Error('ENOENT'); });
57
+ expect(getCachedToken(ACCESS_URL, REALM)).toBeNull();
58
+ });
59
+
60
+ it('returns null when realm is not in cache', () => {
61
+ mockedFs.readFileSync.mockReturnValue(JSON.stringify({ 'other::realm': { accessToken: 'x', expiresAt: futureIso(3600) } }));
62
+ expect(getCachedToken(ACCESS_URL, REALM)).toBeNull();
63
+ });
64
+
65
+ it('returns the cached entry when present', () => {
66
+ const entry: CacheEntry = { accessToken: 'abc', refreshToken: 'ref', expiresAt: futureIso(3600) };
67
+ const key = `${ACCESS_URL}::${REALM}`;
68
+ mockedFs.readFileSync.mockReturnValue(JSON.stringify({ [key]: entry }));
69
+
70
+ expect(getCachedToken(ACCESS_URL, REALM)).toEqual(entry);
71
+ });
72
+ });
73
+
74
+ describe('setCachedToken', () => {
75
+ beforeEach(() => {
76
+ mockedOs.homedir.mockReturnValue(FAKE_HOME);
77
+ mockedFs.existsSync.mockReturnValue(true);
78
+ mockedFs.readFileSync.mockImplementation(() => { throw new Error('ENOENT'); });
79
+ (mockedFs.writeFileSync as jest.Mock).mockReset();
80
+ (mockedFs.mkdirSync as jest.Mock).mockReset();
81
+ });
82
+
83
+ it('writes a new entry with correct fields', () => {
84
+ setCachedToken(ACCESS_URL, REALM, 'access-tok', 'refresh-tok', 3600);
85
+
86
+ expect(mockedFs.writeFileSync).toHaveBeenCalledWith(
87
+ CACHE_PATH,
88
+ expect.stringContaining('"accessToken": "access-tok"'),
89
+ expect.objectContaining({ mode: 0o600 })
90
+ );
91
+
92
+ const written = JSON.parse((mockedFs.writeFileSync as jest.Mock).mock.calls[0][1] as string);
93
+ const entry = written[`${ACCESS_URL}::${REALM}`];
94
+ expect(entry.accessToken).toBe('access-tok');
95
+ expect(entry.refreshToken).toBe('refresh-tok');
96
+ expect(new Date(entry.expiresAt).getTime()).toBeGreaterThan(Date.now() + 3590 * 1000);
97
+ });
98
+
99
+ it('writes without refreshToken when not provided', () => {
100
+ setCachedToken(ACCESS_URL, REALM, 'access-tok', undefined, 3600);
101
+
102
+ const written = JSON.parse((mockedFs.writeFileSync as jest.Mock).mock.calls[0][1] as string);
103
+ const entry = written[`${ACCESS_URL}::${REALM}`];
104
+ expect(entry.refreshToken).toBeUndefined();
105
+ });
106
+
107
+ it('creates the cache directory if it does not exist', () => {
108
+ mockedFs.existsSync.mockReturnValue(false);
109
+
110
+ setCachedToken(ACCESS_URL, REALM, 'tok', undefined, 300);
111
+
112
+ expect(mockedFs.mkdirSync).toHaveBeenCalledWith(
113
+ path.dirname(CACHE_PATH),
114
+ expect.objectContaining({ recursive: true, mode: 0o700 })
115
+ );
116
+ });
117
+ });
@@ -50,7 +50,8 @@ function normalizeOptions(host, options) {
50
50
  });
51
51
  }
52
52
  function addFiles(host, options) {
53
- const templateOptions = Object.assign(Object.assign(Object.assign({}, options), options.adsp), { sourceRepositoryUrl: (0, git_utils_1.getGitRemoteUrl)(), tmpl: '' });
53
+ var _a;
54
+ const templateOptions = Object.assign(Object.assign(Object.assign({}, options), options.adsp), { sourceRepositoryUrl: (0, git_utils_1.getGitRemoteUrl)(), database: (_a = options.database) !== null && _a !== void 0 ? _a : 'none', tmpl: '' });
54
55
  (0, devkit_1.generateFiles)(host, path.join(__dirname, `${options.appType}-files`), `./.openshift/${options.projectName}`, templateOptions);
55
56
  }
56
57
  function default_1(host, options) {
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/deployment/deployment.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"deployment.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/deployment/deployment.ts"],"names":[],"mappings":"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"}
@@ -180,6 +180,64 @@ describe('Deployment Generator', () => {
180
180
  expect(dockerfile).toContain('dotnet');
181
181
  });
182
182
 
183
+ it('includes DATABASE_URL secretKeyRef and init container for postgres node deployment', async () => {
184
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
185
+ await pipeline(host, {
186
+ pipeline: 'test',
187
+ registry: 'ghcr.io/test-org',
188
+ type: 'jenkins',
189
+ infra: 'test-infra',
190
+ envs: 'test-dev',
191
+ });
192
+
193
+ addProjectConfiguration(host, 'test', {
194
+ root: 'apps/test',
195
+ projectType: 'application',
196
+ targets: {
197
+ build: {
198
+ executor: '@nx/webpack:webpack',
199
+ options: { compiler: 'tsc', target: 'node' },
200
+ },
201
+ },
202
+ });
203
+
204
+ await generator(host, { ...options, appType: 'node', database: 'postgres' });
205
+
206
+ const manifest = host.read('.openshift/test/test.yml').toString();
207
+ expect(manifest).toContain('DATABASE_URL');
208
+ expect(manifest).toContain('initContainers');
209
+ expect(manifest).toContain('prisma');
210
+ expect(manifest).toContain('migrate');
211
+ });
212
+
213
+ it('includes MONGODB_URI secretKeyRef without init container for mongo node deployment', async () => {
214
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
215
+ await pipeline(host, {
216
+ pipeline: 'test',
217
+ registry: 'ghcr.io/test-org',
218
+ type: 'jenkins',
219
+ infra: 'test-infra',
220
+ envs: 'test-dev',
221
+ });
222
+
223
+ addProjectConfiguration(host, 'test', {
224
+ root: 'apps/test',
225
+ projectType: 'application',
226
+ targets: {
227
+ build: {
228
+ executor: '@nx/webpack:webpack',
229
+ options: { compiler: 'tsc', target: 'node' },
230
+ },
231
+ },
232
+ });
233
+
234
+ await generator(host, { ...options, appType: 'node', database: 'mongo' });
235
+
236
+ const manifest = host.read('.openshift/test/test.yml').toString();
237
+ expect(manifest).toContain('MONGODB_URI');
238
+ expect(manifest).not.toContain('initContainers');
239
+ });
240
+
183
241
  it('can skip unknown project type', async () => {
184
242
  const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
185
243
  await pipeline(host, {
@@ -75,6 +75,21 @@ objects:
75
75
  labels:
76
76
  name: ${APP_NAME}
77
77
  spec:
78
+ <% if (database === 'postgres') { %>
79
+ initContainers:
80
+ - name: ${APP_NAME}-migrate
81
+ image: image-registry.openshift-image-registry.svc:5000/${INFRA_PROJECT}/${APP_NAME}:${DEPLOY_TAG}
82
+ command: ["npx", "prisma", "migrate", "deploy"]
83
+ envFrom:
84
+ - configMapRef:
85
+ name: ${APP_NAME}
86
+ env:
87
+ - name: DATABASE_URL
88
+ valueFrom:
89
+ secretKeyRef:
90
+ name: ${APP_NAME}-database
91
+ key: DATABASE_URL
92
+ <% } %>
78
93
  containers:
79
94
  - name: ${APP_NAME}
80
95
  image: ${APP_NAME}:${DEPLOY_TAG}
@@ -86,6 +101,21 @@ objects:
86
101
  value: '3333'
87
102
  - name: LOG_LEVEL
88
103
  value: info
104
+ <% if (database === 'postgres') { %>
105
+ # Set via: oc create secret generic ${APP_NAME}-database --from-literal=DATABASE_URL=<connection-string>
106
+ - name: DATABASE_URL
107
+ valueFrom:
108
+ secretKeyRef:
109
+ name: ${APP_NAME}-database
110
+ key: DATABASE_URL
111
+ <% } else if (database === 'mongo') { %>
112
+ # Set via: oc create secret generic ${APP_NAME}-database --from-literal=MONGODB_URI=<connection-string>
113
+ - name: MONGODB_URI
114
+ valueFrom:
115
+ secretKeyRef:
116
+ name: ${APP_NAME}-database
117
+ key: MONGODB_URI
118
+ <% } %>
89
119
  imagePullPolicy: IfNotPresent
90
120
  ports:
91
121
  - containerPort: 3333
@@ -1,6 +1,7 @@
1
1
  import { AdspConfiguration } from '../../adsp';
2
2
 
3
3
  export type ApplicationType = 'node' | 'dotnet' | 'frontend';
4
+ export type DatabaseType = 'none' | 'postgres' | 'mongo';
4
5
 
5
6
  export interface Schema {
6
7
  project: string;
@@ -8,6 +9,7 @@ export interface Schema {
8
9
  env: EnvironmentName;
9
10
  adsp?: AdspConfiguration;
10
11
  accessToken?: string;
12
+ database?: DatabaseType;
11
13
  }
12
14
 
13
15
  export interface NormalizedSchema extends Schema {
@@ -53,6 +53,11 @@
53
53
  "type": "string",
54
54
  "description": "Access token for retrieving configuration from ADSP APIs.",
55
55
  "alias": "at"
56
+ },
57
+ "database": {
58
+ "type": "string",
59
+ "description": "Database type used by the service. When set, the deployment manifest references the appropriate Secret.",
60
+ "enum": ["none", "postgres", "mongo"]
56
61
  }
57
62
  },
58
63
  "required": [