@abgov/nx-oc 12.9.0 → 12.11.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/generators.json CHANGED
@@ -22,6 +22,16 @@
22
22
  "factory": "./src/generators/deployment/deployment",
23
23
  "schema": "./src/generators/deployment/schema.json",
24
24
  "description": "Generator that creates OpenShift manifests for project deployment."
25
+ },
26
+ "sandbox": {
27
+ "factory": "./src/generators/sandbox/sandbox",
28
+ "schema": "./src/generators/sandbox/schema.json",
29
+ "description": "Generator that creates a sandbox deployment for rapid local iteration (local build, push to OC internal registry)."
30
+ },
31
+ "teardown": {
32
+ "factory": "./src/generators/teardown/teardown",
33
+ "schema": "./src/generators/teardown/schema.json",
34
+ "description": "Adds a teardown target to remove an application's resources from a specific OpenShift environment."
25
35
  }
26
36
  }
27
37
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@abgov/nx-oc",
3
- "version": "12.9.0",
3
+ "version": "12.11.0",
4
4
  "license": "Apache-2.0",
5
5
  "main": "src/index.js",
6
6
  "description": "Government of Alberta - Nx plugin for OpenShift.",
@@ -50,8 +50,8 @@ function normalizeOptions(host, options) {
50
50
  });
51
51
  }
52
52
  function addFiles(host, options) {
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: '' });
53
+ var _a, _b;
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', sandbox: (_b = options.sandbox) !== null && _b !== void 0 ? _b : false, tmpl: '' });
55
55
  (0, devkit_1.generateFiles)(host, path.join(__dirname, `${options.appType}-files`), `./.openshift/${options.projectName}`, templateOptions);
56
56
  }
57
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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"}
@@ -5,11 +5,13 @@ metadata:
5
5
  labels:
6
6
  app: <%= projectName %>
7
7
  parameters:
8
+ <% if (!sandbox) { %>
8
9
  - name: INFRA_PROJECT
9
10
  description: Project used for build infrastructure.
10
11
  displayName: Infrastructure Project
11
12
  value: <%= ocInfraProject %>
12
13
  required: true
14
+ <% } %>
13
15
  - name: PROJECT
14
16
  description: Project to deploy into.
15
17
  displayName: Project
@@ -19,17 +21,21 @@ parameters:
19
21
  displayName: Application Name
20
22
  value: <%= projectName %>
21
23
  required: true
24
+ <% if (!sandbox) { %>
22
25
  - name: DEPLOY_TAG
23
26
  description: ImageStream tag to deploy.
24
27
  displayName: Deploy Tag
25
28
  value: latest
26
29
  required: true
30
+ <% } %>
27
31
  objects:
32
+ <% if (!sandbox) { %>
28
33
  - apiVersion: image.openshift.io/v1
29
34
  kind: ImageStream
30
35
  metadata:
31
36
  name: ${APP_NAME}
32
37
  namespace: ${INFRA_PROJECT}
38
+ <% } %>
33
39
  - apiVersion: v1
34
40
  kind: ConfigMap
35
41
  metadata:
@@ -61,6 +67,7 @@ objects:
61
67
  metadata:
62
68
  name: ${APP_NAME}
63
69
  namespace: ${PROJECT}
70
+ <% if (!sandbox) { %>
64
71
  annotations:
65
72
  image.openshift.io/triggers: |-
66
73
  [
@@ -74,6 +81,7 @@ objects:
74
81
  "paused": true
75
82
  }
76
83
  ]
84
+ <% } %>
77
85
  spec:
78
86
  replicas: 1
79
87
  selector:
@@ -93,14 +101,18 @@ objects:
93
101
  spec:
94
102
  containers:
95
103
  - name: ${APP_NAME}
104
+ <% if (sandbox) { %>
105
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
106
+ <% } else { %>
96
107
  image: ${APP_NAME}:${DEPLOY_TAG}
108
+ <% } %>
97
109
  envFrom:
98
110
  - configMapRef:
99
111
  name: ${APP_NAME}
100
112
  env:
101
113
  - name: LOG_LEVEL
102
114
  value: info
103
- imagePullPolicy: IfNotPresent
115
+ imagePullPolicy: <%= sandbox ? 'Always' : 'IfNotPresent' %>
104
116
  ports:
105
117
  - containerPort: 5000
106
118
  name: http
@@ -5,11 +5,13 @@ metadata:
5
5
  labels:
6
6
  app: <%= projectName %>
7
7
  parameters:
8
+ <% if (!sandbox) { %>
8
9
  - name: INFRA_PROJECT
9
10
  description: Project used for build infrastructure.
10
11
  displayName: Infrastructure Project
11
12
  value: <%= ocInfraProject %>
12
13
  required: true
14
+ <% } %>
13
15
  - name: PROJECT
14
16
  description: Project to deploy into.
15
17
  displayName: Project
@@ -19,17 +21,21 @@ parameters:
19
21
  displayName: Application Name
20
22
  value: <%= projectName %>
21
23
  required: true
24
+ <% if (!sandbox) { %>
22
25
  - name: DEPLOY_TAG
23
26
  description: ImageStream tag to deploy.
24
27
  displayName: Deploy Tag
25
28
  value: latest
26
29
  required: true
30
+ <% } %>
27
31
  objects:
32
+ <% if (!sandbox) { %>
28
33
  - apiVersion: image.openshift.io/v1
29
34
  kind: ImageStream
30
35
  metadata:
31
36
  name: ${APP_NAME}
32
37
  namespace: ${INFRA_PROJECT}
38
+ <% } %>
33
39
  - apiVersion: v1
34
40
  kind: ConfigMap
35
41
  metadata:
@@ -51,6 +57,7 @@ objects:
51
57
  metadata:
52
58
  name: ${APP_NAME}
53
59
  namespace: ${PROJECT}
60
+ <% if (!sandbox) { %>
54
61
  annotations:
55
62
  image.openshift.io/triggers: |-
56
63
  [
@@ -64,6 +71,7 @@ objects:
64
71
  "paused": true
65
72
  }
66
73
  ]
74
+ <% } %>
67
75
  spec:
68
76
  replicas: 1
69
77
  selector:
@@ -83,8 +91,12 @@ objects:
83
91
  spec:
84
92
  containers:
85
93
  - name: ${APP_NAME}
94
+ <% if (sandbox) { %>
95
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
96
+ <% } else { %>
86
97
  image: ${APP_NAME}:${DEPLOY_TAG}
87
- imagePullPolicy: IfNotPresent
98
+ <% } %>
99
+ imagePullPolicy: <%= sandbox ? 'Always' : 'IfNotPresent' %>
88
100
  ports:
89
101
  - containerPort: 8080
90
102
  name: http
@@ -5,11 +5,13 @@ metadata:
5
5
  labels:
6
6
  app: <%= projectName %>
7
7
  parameters:
8
+ <% if (!sandbox) { %>
8
9
  - name: INFRA_PROJECT
9
10
  description: Project used for build infrastructure.
10
11
  displayName: Infrastructure Project
11
12
  value: <%= ocInfraProject %>
12
13
  required: true
14
+ <% } %>
13
15
  - name: PROJECT
14
16
  description: Project to deploy into.
15
17
  displayName: Project
@@ -19,17 +21,21 @@ parameters:
19
21
  displayName: Application Name
20
22
  value: <%= projectName %>
21
23
  required: true
24
+ <% if (!sandbox) { %>
22
25
  - name: DEPLOY_TAG
23
26
  description: ImageStream tag to deploy.
24
27
  displayName: Deploy Tag
25
28
  value: latest
26
29
  required: true
30
+ <% } %>
27
31
  objects:
32
+ <% if (!sandbox) { %>
28
33
  - apiVersion: image.openshift.io/v1
29
34
  kind: ImageStream
30
35
  metadata:
31
36
  name: ${APP_NAME}
32
37
  namespace: ${INFRA_PROJECT}
38
+ <% } %>
33
39
  - apiVersion: v1
34
40
  kind: ConfigMap
35
41
  metadata:
@@ -45,6 +51,7 @@ objects:
45
51
  metadata:
46
52
  name: ${APP_NAME}
47
53
  namespace: ${PROJECT}
54
+ <% if (!sandbox) { %>
48
55
  annotations:
49
56
  image.openshift.io/triggers: |-
50
57
  [
@@ -58,6 +65,7 @@ objects:
58
65
  "paused": true
59
66
  }
60
67
  ]
68
+ <% } %>
61
69
  spec:
62
70
  replicas: 1
63
71
  selector:
@@ -78,21 +86,39 @@ objects:
78
86
  <% if (database === 'postgres') { %>
79
87
  initContainers:
80
88
  - name: ${APP_NAME}-migrate
89
+ <% if (sandbox) { %>
90
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
91
+ <% } else { %>
81
92
  image: image-registry.openshift-image-registry.svc:5000/${INFRA_PROJECT}/${APP_NAME}:${DEPLOY_TAG}
93
+ <% } %>
82
94
  command: ["npx", "prisma", "migrate", "deploy"]
83
95
  envFrom:
84
96
  - configMapRef:
85
97
  name: ${APP_NAME}
86
98
  env:
99
+ <% if (sandbox) { %>
100
+ - name: POSTGRES_PASSWORD
101
+ valueFrom:
102
+ secretKeyRef:
103
+ name: sandbox-postgres-creds
104
+ key: POSTGRESQL_ADMIN_PASSWORD
105
+ - name: DATABASE_URL
106
+ value: postgresql://postgres:$(POSTGRES_PASSWORD)@sandbox-postgres:5432/<%= projectName %>_sandbox
107
+ <% } else { %>
87
108
  - name: DATABASE_URL
88
109
  valueFrom:
89
110
  secretKeyRef:
90
111
  name: ${APP_NAME}-database
91
112
  key: DATABASE_URL
113
+ <% } %>
92
114
  <% } %>
93
115
  containers:
94
116
  - name: ${APP_NAME}
117
+ <% if (sandbox) { %>
118
+ image: image-registry.openshift-image-registry.svc:5000/${PROJECT}/<%= projectName %>:sandbox
119
+ <% } else { %>
95
120
  image: ${APP_NAME}:${DEPLOY_TAG}
121
+ <% } %>
96
122
  envFrom:
97
123
  - configMapRef:
98
124
  name: ${APP_NAME}
@@ -102,13 +128,32 @@ objects:
102
128
  - name: LOG_LEVEL
103
129
  value: info
104
130
  <% if (database === 'postgres') { %>
131
+ <% if (sandbox) { %>
132
+ - name: POSTGRES_PASSWORD
133
+ valueFrom:
134
+ secretKeyRef:
135
+ name: sandbox-postgres-creds
136
+ key: POSTGRESQL_ADMIN_PASSWORD
137
+ - name: DATABASE_URL
138
+ value: postgresql://postgres:$(POSTGRES_PASSWORD)@sandbox-postgres:5432/<%= projectName %>_sandbox
139
+ <% } else { %>
105
140
  # Set via: oc create secret generic ${APP_NAME}-database --from-literal=DATABASE_URL=<connection-string>
106
141
  - name: DATABASE_URL
107
142
  valueFrom:
108
143
  secretKeyRef:
109
144
  name: ${APP_NAME}-database
110
145
  key: DATABASE_URL
146
+ <% } %>
111
147
  <% } else if (database === 'mongo') { %>
148
+ <% if (sandbox) { %>
149
+ - name: MONGO_PASSWORD
150
+ valueFrom:
151
+ secretKeyRef:
152
+ name: sandbox-mongodb-creds
153
+ key: MONGODB_ADMIN_PASSWORD
154
+ - name: MONGODB_URI
155
+ value: mongodb://admin:$(MONGO_PASSWORD)@sandbox-mongodb:27017/<%= projectName %>_sandbox?authSource=admin
156
+ <% } else { %>
112
157
  # Set via: oc create secret generic ${APP_NAME}-database --from-literal=MONGODB_URI=<connection-string>
113
158
  - name: MONGODB_URI
114
159
  valueFrom:
@@ -116,7 +161,8 @@ objects:
116
161
  name: ${APP_NAME}-database
117
162
  key: MONGODB_URI
118
163
  <% } %>
119
- imagePullPolicy: IfNotPresent
164
+ <% } %>
165
+ imagePullPolicy: <%= sandbox ? 'Always' : 'IfNotPresent' %>
120
166
  ports:
121
167
  - containerPort: 3333
122
168
  name: http
@@ -10,6 +10,7 @@ export interface Schema {
10
10
  adsp?: AdspConfiguration;
11
11
  accessToken?: string;
12
12
  database?: DatabaseType;
13
+ sandbox?: boolean;
13
14
  }
14
15
 
15
16
  export interface NormalizedSchema extends Schema {
@@ -58,6 +58,10 @@
58
58
  "type": "string",
59
59
  "description": "Database type used by the service. When set, the deployment manifest references the appropriate Secret.",
60
60
  "enum": ["none", "postgres", "mongo"]
61
+ },
62
+ "sandbox": {
63
+ "type": "boolean",
64
+ "description": "Generate a sandbox deployment manifest (local image push, no ImageStream trigger)."
61
65
  }
62
66
  },
63
67
  "required": [
@@ -0,0 +1,104 @@
1
+ # Shared MongoDB instance for the sandbox namespace on GoA ARO OpenShift.
2
+ # Applied once per namespace — idempotent, safe to re-run. The PVC is never
3
+ # deleted on re-apply, so data persists across deployments.
4
+ #
5
+ # Multiple apps in the same namespace share this instance. Each app uses its
6
+ # own database (<appName>_sandbox); MongoDB creates it on first write.
7
+ #
8
+ # Credentials are stored in the sandbox-mongodb-creds Secret, created once
9
+ # per namespace by `nx run <app>:sandbox` on first use. Subsequent apps read
10
+ # from the same Secret so all apps share consistent credentials.
11
+ #
12
+ # StorageClass: azure-disk is required on GoA ARO.
13
+ ---
14
+ apiVersion: v1
15
+ kind: PersistentVolumeClaim
16
+ metadata:
17
+ name: sandbox-mongodb-data
18
+ spec:
19
+ storageClassName: azure-disk
20
+ accessModes:
21
+ - ReadWriteOnce
22
+ resources:
23
+ requests:
24
+ storage: 5Gi
25
+ ---
26
+ apiVersion: apps/v1
27
+ kind: Deployment
28
+ metadata:
29
+ name: sandbox-mongodb
30
+ labels:
31
+ app: sandbox-mongodb
32
+ spec:
33
+ replicas: 1
34
+ selector:
35
+ matchLabels:
36
+ app: sandbox-mongodb
37
+ strategy:
38
+ type: Recreate
39
+ template:
40
+ metadata:
41
+ labels:
42
+ app: sandbox-mongodb
43
+ spec:
44
+ containers:
45
+ - name: mongodb
46
+ image: quay.io/sclorg/mongodb-70-c9s:latest
47
+ ports:
48
+ - containerPort: 27017
49
+ protocol: TCP
50
+ env:
51
+ - name: MONGODB_ADMIN_PASSWORD
52
+ valueFrom:
53
+ secretKeyRef:
54
+ name: sandbox-mongodb-creds
55
+ key: MONGODB_ADMIN_PASSWORD
56
+ volumeMounts:
57
+ - name: data
58
+ mountPath: /var/lib/mongodb/data
59
+ readinessProbe:
60
+ exec:
61
+ command:
62
+ - mongosh
63
+ - --eval
64
+ - "db.adminCommand('ping')"
65
+ initialDelaySeconds: 10
66
+ periodSeconds: 10
67
+ timeoutSeconds: 5
68
+ failureThreshold: 3
69
+ livenessProbe:
70
+ exec:
71
+ command:
72
+ - mongosh
73
+ - --eval
74
+ - "db.adminCommand('ping')"
75
+ initialDelaySeconds: 30
76
+ periodSeconds: 20
77
+ timeoutSeconds: 5
78
+ failureThreshold: 3
79
+ resources:
80
+ requests:
81
+ cpu: "100m"
82
+ memory: "256Mi"
83
+ limits:
84
+ cpu: "500m"
85
+ memory: "512Mi"
86
+ volumes:
87
+ - name: data
88
+ persistentVolumeClaim:
89
+ claimName: sandbox-mongodb-data
90
+ ---
91
+ apiVersion: v1
92
+ kind: Service
93
+ metadata:
94
+ name: sandbox-mongodb
95
+ labels:
96
+ app: sandbox-mongodb
97
+ spec:
98
+ selector:
99
+ app: sandbox-mongodb
100
+ ports:
101
+ - name: mongodb
102
+ port: 27017
103
+ targetPort: 27017
104
+ protocol: TCP
@@ -0,0 +1,100 @@
1
+ # Shared Postgres instance for the sandbox namespace on GoA ARO OpenShift.
2
+ # Applied once per namespace — idempotent, safe to re-run. The PVC is never
3
+ # deleted on re-apply, so data persists across deployments.
4
+ #
5
+ # Multiple apps in the same namespace share this instance. Each app uses its
6
+ # own database (<appName>_sandbox) created automatically by Prisma migrate.
7
+ #
8
+ # Credentials are stored in the sandbox-postgres-creds Secret, created once
9
+ # per namespace by `nx run <app>:sandbox` on first use. Subsequent apps read
10
+ # from the same Secret so all apps share consistent credentials.
11
+ #
12
+ # StorageClass: azure-disk is required on GoA ARO.
13
+ # azure-file will NOT work: SMB mounts with root ownership and Postgres
14
+ # refuses to start on a data directory it does not own.
15
+ ---
16
+ apiVersion: v1
17
+ kind: PersistentVolumeClaim
18
+ metadata:
19
+ name: sandbox-postgres-data
20
+ spec:
21
+ storageClassName: azure-disk
22
+ accessModes:
23
+ - ReadWriteOnce
24
+ resources:
25
+ requests:
26
+ storage: 5Gi
27
+ ---
28
+ apiVersion: apps/v1
29
+ kind: Deployment
30
+ metadata:
31
+ name: sandbox-postgres
32
+ labels:
33
+ app: sandbox-postgres
34
+ spec:
35
+ replicas: 1
36
+ selector:
37
+ matchLabels:
38
+ app: sandbox-postgres
39
+ strategy:
40
+ type: Recreate
41
+ template:
42
+ metadata:
43
+ labels:
44
+ app: sandbox-postgres
45
+ spec:
46
+ containers:
47
+ - name: postgres
48
+ image: quay.io/sclorg/postgresql-16-c9s:latest
49
+ ports:
50
+ - containerPort: 5432
51
+ protocol: TCP
52
+ env:
53
+ - name: POSTGRESQL_ADMIN_PASSWORD
54
+ valueFrom:
55
+ secretKeyRef:
56
+ name: sandbox-postgres-creds
57
+ key: POSTGRESQL_ADMIN_PASSWORD
58
+ volumeMounts:
59
+ - name: data
60
+ mountPath: /var/lib/pgsql/data
61
+ readinessProbe:
62
+ exec:
63
+ command: ["pg_isready", "-U", "postgres"]
64
+ initialDelaySeconds: 5
65
+ periodSeconds: 10
66
+ timeoutSeconds: 3
67
+ failureThreshold: 3
68
+ livenessProbe:
69
+ exec:
70
+ command: ["pg_isready", "-U", "postgres"]
71
+ initialDelaySeconds: 15
72
+ periodSeconds: 20
73
+ timeoutSeconds: 5
74
+ failureThreshold: 3
75
+ resources:
76
+ requests:
77
+ cpu: "100m"
78
+ memory: "256Mi"
79
+ limits:
80
+ cpu: "500m"
81
+ memory: "512Mi"
82
+ volumes:
83
+ - name: data
84
+ persistentVolumeClaim:
85
+ claimName: sandbox-postgres-data
86
+ ---
87
+ apiVersion: v1
88
+ kind: Service
89
+ metadata:
90
+ name: sandbox-postgres
91
+ labels:
92
+ app: sandbox-postgres
93
+ spec:
94
+ selector:
95
+ app: sandbox-postgres
96
+ ports:
97
+ - name: postgres
98
+ port: 5432
99
+ targetPort: 5432
100
+ protocol: TCP
@@ -0,0 +1,3 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { Schema } from './schema';
3
+ export default function (host: Tree, options: Schema): Promise<void>;
@@ -0,0 +1,106 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const path = require("path");
7
+ const adsp_1 = require("../../adsp");
8
+ const git_utils_1 = require("../../utils/git-utils");
9
+ function normalizeOptions(host, options) {
10
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
11
+ var _a;
12
+ const projectName = (0, devkit_1.names)(options.project).fileName;
13
+ const config = (0, devkit_1.readProjectConfiguration)(host, projectName);
14
+ let appType = options.appType;
15
+ if (!appType) {
16
+ switch (config.targets.build.executor) {
17
+ case '@nx/web:webpack':
18
+ case '@angular-devkit/build-angular:browser':
19
+ appType = 'frontend';
20
+ break;
21
+ case '@nx/node:build':
22
+ appType = 'node';
23
+ break;
24
+ case '@nx-dotnet/core:build':
25
+ appType = 'dotnet';
26
+ break;
27
+ case '@nx/webpack:webpack':
28
+ appType =
29
+ config.targets.build.options.target === 'node' ? 'node' : 'frontend';
30
+ break;
31
+ }
32
+ }
33
+ const adsp = yield (0, adsp_1.getAdspConfiguration)(host, Object.assign(Object.assign({}, options), { env: (_a = options.env) !== null && _a !== void 0 ? _a : 'dev' }));
34
+ return Object.assign(Object.assign({}, options), { appType,
35
+ adsp,
36
+ projectName });
37
+ });
38
+ }
39
+ function addManifestFiles(host, options) {
40
+ var _a;
41
+ 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', sandbox: true, ocInfraProject: options.sandboxProject, tmpl: '' });
42
+ (0, devkit_1.generateFiles)(host, path.join(__dirname, `../deployment/${options.appType}-files`), `./.openshift/${options.projectName}`, templateOptions);
43
+ }
44
+ function addDatabaseFiles(host, options) {
45
+ if (!options.database || options.database === 'none')
46
+ return;
47
+ (0, devkit_1.generateFiles)(host, path.join(__dirname, 'database-files'), './.openshift/sandbox', { database: options.database, tmpl: '' });
48
+ }
49
+ function addSandboxTarget(host, options) {
50
+ const config = (0, devkit_1.readProjectConfiguration)(host, options.project);
51
+ const { projectName, sandboxProject, database } = options;
52
+ const commands = [];
53
+ if (database === 'postgres') {
54
+ commands.push(`oc get secret sandbox-postgres-creds -n ${sandboxProject} 2>/dev/null || ` +
55
+ `oc create secret generic sandbox-postgres-creds ` +
56
+ `--from-literal=POSTGRESQL_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=') ` +
57
+ `-n ${sandboxProject}`);
58
+ commands.push(`oc apply -f .openshift/sandbox/sandbox-postgres.yml -n ${sandboxProject}`);
59
+ }
60
+ else if (database === 'mongo') {
61
+ commands.push(`oc get secret sandbox-mongodb-creds -n ${sandboxProject} 2>/dev/null || ` +
62
+ `oc create secret generic sandbox-mongodb-creds ` +
63
+ `--from-literal=MONGODB_ADMIN_PASSWORD=$(openssl rand -base64 24 | tr -d '/+=') ` +
64
+ `-n ${sandboxProject}`);
65
+ commands.push(`oc apply -f .openshift/sandbox/sandbox-mongodb.yml -n ${sandboxProject}`);
66
+ }
67
+ commands.push(`oc process -f .openshift/${projectName}/${projectName}.yml -p PROJECT=${sandboxProject} | oc apply -f -`);
68
+ commands.push([
69
+ `REGISTRY=$(oc registry info)`,
70
+ `CONTAINER_CLI=$(command -v podman || command -v docker)`,
71
+ `$CONTAINER_CLI login -u $(oc whoami) -p $(oc whoami -t) $REGISTRY`,
72
+ `$CONTAINER_CLI build -t $REGISTRY/${sandboxProject}/${projectName}:sandbox -f .openshift/${projectName}/Dockerfile .`,
73
+ `$CONTAINER_CLI push $REGISTRY/${sandboxProject}/${projectName}:sandbox`,
74
+ ].join(' && '));
75
+ commands.push(`oc rollout restart deployment/${projectName} -n ${sandboxProject}`);
76
+ commands.push(`oc rollout status deployment/${projectName} -n ${sandboxProject} --timeout=120s`);
77
+ config.targets = Object.assign(Object.assign({}, config.targets), { sandbox: {
78
+ executor: 'nx:run-commands',
79
+ options: {
80
+ commands,
81
+ sequential: true,
82
+ },
83
+ }, 'sandbox-teardown': {
84
+ executor: 'nx:run-commands',
85
+ options: {
86
+ commands: [
87
+ `oc delete all,configmap -l app=${projectName} -n ${sandboxProject} --ignore-not-found`,
88
+ ],
89
+ },
90
+ } });
91
+ (0, devkit_1.updateProjectConfiguration)(host, options.project, config);
92
+ }
93
+ function default_1(host, options) {
94
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
95
+ const normalizedOptions = yield normalizeOptions(host, options);
96
+ if (!normalizedOptions.appType) {
97
+ console.log('Cannot generate sandbox deployment for unknown project type.');
98
+ return;
99
+ }
100
+ addManifestFiles(host, normalizedOptions);
101
+ addDatabaseFiles(host, normalizedOptions);
102
+ addSandboxTarget(host, normalizedOptions);
103
+ yield (0, devkit_1.formatFiles)(host);
104
+ });
105
+ }
106
+ //# sourceMappingURL=sandbox.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sandbox.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/sandbox/sandbox.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,149 @@
1
+ import {
2
+ addProjectConfiguration,
3
+ readProjectConfiguration,
4
+ } from '@nx/devkit';
5
+ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
6
+ import * as utils from '../../adsp';
7
+ import { environments } from '../../adsp';
8
+ import generator from './sandbox';
9
+ import { Schema } from './schema';
10
+
11
+ jest.mock('../../adsp');
12
+ const utilsMock = utils as jest.Mocked<typeof utils>;
13
+ utilsMock.getAdspConfiguration.mockResolvedValue({
14
+ tenant: 'test',
15
+ tenantRealm: 'test',
16
+ accessServiceUrl: environments.test.accessServiceUrl,
17
+ directoryServiceUrl: environments.test.directoryServiceUrl,
18
+ });
19
+
20
+ describe('Sandbox Generator', () => {
21
+ const options: Schema = {
22
+ project: 'test',
23
+ sandboxProject: 'test-sandbox',
24
+ };
25
+
26
+ function addNodeProject(host) {
27
+ addProjectConfiguration(host, 'test', {
28
+ root: 'apps/test',
29
+ projectType: 'application',
30
+ targets: {
31
+ build: {
32
+ executor: '@nx/webpack:webpack',
33
+ options: { compiler: 'tsc', target: 'node' },
34
+ },
35
+ },
36
+ });
37
+ }
38
+
39
+ function addFrontendProject(host) {
40
+ addProjectConfiguration(host, 'test', {
41
+ root: 'apps/test',
42
+ projectType: 'application',
43
+ targets: {
44
+ build: {
45
+ executor: '@nx/webpack:webpack',
46
+ options: { compiler: 'babel' },
47
+ },
48
+ },
49
+ });
50
+ }
51
+
52
+ it('generates sandbox manifest for node app', async () => {
53
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
54
+ addNodeProject(host);
55
+
56
+ await generator(host, options);
57
+
58
+ expect(host.exists('.openshift/test/test.yml')).toBeTruthy();
59
+ const manifest = host.read('.openshift/test/test.yml').toString();
60
+ expect(manifest).toContain('imagePullPolicy: Always');
61
+ expect(manifest).not.toContain('ImageStream');
62
+ expect(manifest).not.toContain('DEPLOY_TAG');
63
+ expect(manifest).toContain('sandbox');
64
+ });
65
+
66
+ it('generates sandbox manifest for frontend app', async () => {
67
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
68
+ addFrontendProject(host);
69
+
70
+ await generator(host, options);
71
+
72
+ expect(host.exists('.openshift/test/test.yml')).toBeTruthy();
73
+ const manifest = host.read('.openshift/test/test.yml').toString();
74
+ expect(manifest).toContain('imagePullPolicy: Always');
75
+ expect(manifest).not.toContain('ImageStream');
76
+ });
77
+
78
+ it('adds sandbox nx target', async () => {
79
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
80
+ addNodeProject(host);
81
+
82
+ await generator(host, options);
83
+
84
+ const config = readProjectConfiguration(host, 'test');
85
+ expect(config.targets['sandbox']).toBeTruthy();
86
+ expect(config.targets['sandbox'].executor).toBe('nx:run-commands');
87
+ const cmds: string[] = config.targets['sandbox'].options.commands;
88
+ expect(cmds.some((c) => c.includes('oc rollout restart'))).toBeTruthy();
89
+ expect(cmds.some((c) => c.includes('oc rollout status'))).toBeTruthy();
90
+ expect(cmds.some((c) => c.includes('command -v podman'))).toBeTruthy();
91
+ });
92
+
93
+ it('adds sandbox-teardown nx target', async () => {
94
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
95
+ addNodeProject(host);
96
+
97
+ await generator(host, options);
98
+
99
+ const config = readProjectConfiguration(host, 'test');
100
+ expect(config.targets['sandbox-teardown']).toBeTruthy();
101
+ const cmds: string[] = config.targets['sandbox-teardown'].options.commands;
102
+ expect(cmds.some((c) => c.includes('oc delete'))).toBeTruthy();
103
+ expect(cmds.some((c) => c.includes('--ignore-not-found'))).toBeTruthy();
104
+ expect(cmds.some((c) => c.includes('test-sandbox'))).toBeTruthy();
105
+ expect(cmds.some((c) => c.includes('-l app=test'))).toBeTruthy();
106
+ expect(cmds.some((c) => c.includes('all,configmap'))).toBeTruthy();
107
+ });
108
+
109
+ it('generates shared postgres manifest with secret-backed DATABASE_URL', async () => {
110
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
111
+ addNodeProject(host);
112
+
113
+ await generator(host, { ...options, database: 'postgres' });
114
+
115
+ expect(host.exists('.openshift/sandbox/sandbox-postgres.yml')).toBeTruthy();
116
+
117
+ const dbManifest = host.read('.openshift/sandbox/sandbox-postgres.yml').toString();
118
+ expect(dbManifest).toContain('sandbox-postgres-creds');
119
+
120
+ const appManifest = host.read('.openshift/test/test.yml').toString();
121
+ expect(appManifest).toContain('sandbox-postgres-creds');
122
+ expect(appManifest).toContain('$(POSTGRES_PASSWORD)');
123
+
124
+ const config = readProjectConfiguration(host, 'test');
125
+ const cmds: string[] = config.targets['sandbox'].options.commands;
126
+ expect(cmds.some((c) => c.includes('sandbox-postgres-creds'))).toBeTruthy();
127
+ expect(cmds.some((c) => c.includes('sandbox-postgres.yml'))).toBeTruthy();
128
+ });
129
+
130
+ it('generates shared mongodb manifest with secret-backed MONGODB_URI', async () => {
131
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
132
+ addNodeProject(host);
133
+
134
+ await generator(host, { ...options, database: 'mongo' });
135
+
136
+ expect(host.exists('.openshift/sandbox/sandbox-mongodb.yml')).toBeTruthy();
137
+
138
+ const dbManifest = host.read('.openshift/sandbox/sandbox-mongodb.yml').toString();
139
+ expect(dbManifest).toContain('sandbox-mongodb-creds');
140
+
141
+ const appManifest = host.read('.openshift/test/test.yml').toString();
142
+ expect(appManifest).toContain('sandbox-mongodb-creds');
143
+ expect(appManifest).toContain('$(MONGO_PASSWORD)');
144
+
145
+ const config = readProjectConfiguration(host, 'test');
146
+ const cmds: string[] = config.targets['sandbox'].options.commands;
147
+ expect(cmds.some((c) => c.includes('sandbox-mongodb-creds'))).toBeTruthy();
148
+ });
149
+ });
@@ -0,0 +1,18 @@
1
+ import { AdspConfiguration } from '../../adsp';
2
+ import { ApplicationType, DatabaseType } from '../deployment/schema';
3
+
4
+ export interface Schema {
5
+ project: string;
6
+ appType?: ApplicationType;
7
+ sandboxProject: string;
8
+ database?: DatabaseType;
9
+ env?: string;
10
+ adsp?: AdspConfiguration;
11
+ accessToken?: string;
12
+ }
13
+
14
+ export interface NormalizedSchema extends Schema {
15
+ projectName: string;
16
+ appType: ApplicationType;
17
+ adsp: AdspConfiguration;
18
+ }
@@ -0,0 +1,50 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "id": "NxOcSandbox",
4
+ "title": "OpenShift Sandbox Deployment",
5
+ "type": "object",
6
+ "properties": {
7
+ "project": {
8
+ "type": "string",
9
+ "description": "Project to add sandbox deployment for.",
10
+ "$default": {
11
+ "$source": "argv",
12
+ "index": 0
13
+ },
14
+ "x-prompt": "Which project to add sandbox deployment for?"
15
+ },
16
+ "sandboxProject": {
17
+ "type": "string",
18
+ "description": "OpenShift namespace to deploy the sandbox into.",
19
+ "alias": "s",
20
+ "x-prompt": "Which OpenShift namespace should be used for the sandbox?"
21
+ },
22
+ "appType": {
23
+ "type": "string",
24
+ "description": "Type of application.",
25
+ "alias": "t",
26
+ "x-prompt": {
27
+ "message": "What type of application is the project?",
28
+ "type": "list",
29
+ "items": ["frontend", "dotnet", "node"]
30
+ }
31
+ },
32
+ "database": {
33
+ "type": "string",
34
+ "description": "Database type. A shared containerized instance will be deployed to the sandbox namespace.",
35
+ "enum": ["none", "postgres", "mongo"]
36
+ },
37
+ "env": {
38
+ "type": "string",
39
+ "description": "ADSP environment to target.",
40
+ "default": "dev"
41
+ },
42
+ "accessToken": {
43
+ "type": "string",
44
+ "description": "Access token for retrieving configuration from ADSP APIs.",
45
+ "alias": "at"
46
+ }
47
+ },
48
+ "required": ["project", "sandboxProject"],
49
+ "additionalProperties": false
50
+ }
@@ -0,0 +1,10 @@
1
+ export interface Schema {
2
+ project: string;
3
+ env: 'dev' | 'test' | 'prod';
4
+ }
5
+
6
+ export interface NormalizedSchema extends Schema {
7
+ projectName: string;
8
+ envProject: string;
9
+ ocInfraProject: string;
10
+ }
@@ -0,0 +1,33 @@
1
+ {
2
+ "$schema": "http://json-schema.org/schema",
3
+ "id": "NxOcTeardown",
4
+ "title": "OpenShift Environment Teardown",
5
+ "type": "object",
6
+ "properties": {
7
+ "project": {
8
+ "type": "string",
9
+ "description": "Project to add teardown target for.",
10
+ "$default": {
11
+ "$source": "argv",
12
+ "index": 0
13
+ },
14
+ "x-prompt": "Which project to add teardown for?"
15
+ },
16
+ "env": {
17
+ "type": "string",
18
+ "description": "Environment to target for teardown.",
19
+ "$default": {
20
+ "$source": "argv",
21
+ "index": 1
22
+ },
23
+ "alias": "e",
24
+ "x-prompt": {
25
+ "message": "Which environment to target?",
26
+ "type": "list",
27
+ "items": ["dev", "test", "prod"]
28
+ }
29
+ }
30
+ },
31
+ "required": ["project", "env"],
32
+ "additionalProperties": false
33
+ }
@@ -0,0 +1,3 @@
1
+ import { Tree } from '@nx/devkit';
2
+ import { Schema } from './schema';
3
+ export default function (host: Tree, options: Schema): Promise<void>;
@@ -0,0 +1,48 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.default = default_1;
4
+ const tslib_1 = require("tslib");
5
+ const devkit_1 = require("@nx/devkit");
6
+ const yaml = require("yaml");
7
+ const pipeline_envs_1 = require("../../pipeline-envs");
8
+ const infraManifestFile = '.openshift/environments.yml';
9
+ function normalizeOptions(host, options) {
10
+ var _a, _b, _c, _d;
11
+ const projectName = (0, devkit_1.names)(options.project).fileName;
12
+ const result = host.read(infraManifestFile).toString();
13
+ const { items } = yaml.parse(result);
14
+ const ocInfraProject = ((_b = (_a = items[0]) === null || _a === void 0 ? void 0 : _a.metadata) === null || _b === void 0 ? void 0 : _b.namespace) || '';
15
+ const SA_PREFIX = 'system:serviceaccounts:';
16
+ const ocEnvProjects = (_d = (_c = items[0]) === null || _c === void 0 ? void 0 : _c.subjects) === null || _d === void 0 ? void 0 : _d.filter((s) => s.kind === 'Group' && s.name.startsWith(SA_PREFIX)).map((s) => s.name.replace(SA_PREFIX, ''));
17
+ const envIndex = pipeline_envs_1.pipelineEnvs.map((e) => e.toLowerCase()).indexOf(options.env.toLowerCase());
18
+ const envProject = (ocEnvProjects === null || ocEnvProjects === void 0 ? void 0 : ocEnvProjects[envIndex]) || '';
19
+ return Object.assign(Object.assign({}, options), { projectName,
20
+ ocInfraProject,
21
+ envProject });
22
+ }
23
+ function default_1(host, options) {
24
+ return tslib_1.__awaiter(this, void 0, void 0, function* () {
25
+ if (!host.exists(infraManifestFile)) {
26
+ console.log(`Cannot generate teardown; run 'nx g @abgov/nx-oc:pipeline' first.`);
27
+ return;
28
+ }
29
+ const normalizedOptions = normalizeOptions(host, options);
30
+ if (!normalizedOptions.envProject) {
31
+ console.log(`Cannot find project for environment '${options.env}'.`);
32
+ return;
33
+ }
34
+ const config = (0, devkit_1.readProjectConfiguration)(host, options.project);
35
+ const { projectName, envProject } = normalizedOptions;
36
+ config.targets = Object.assign(Object.assign({}, config.targets), { [`teardown-${options.env}`]: {
37
+ executor: 'nx:run-commands',
38
+ options: {
39
+ commands: [
40
+ `oc delete all,configmap -l app=${projectName} -n ${envProject} --ignore-not-found`,
41
+ ],
42
+ },
43
+ } });
44
+ (0, devkit_1.updateProjectConfiguration)(host, options.project, config);
45
+ yield (0, devkit_1.formatFiles)(host);
46
+ });
47
+ }
48
+ //# sourceMappingURL=teardown.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"teardown.js","sourceRoot":"","sources":["../../../../../../packages/nx-oc/src/generators/teardown/teardown.ts"],"names":[],"mappings":";;AAoCA,4BA6BC;;AAjED,uCAMoB;AACpB,6BAA6B;AAC7B,uDAA2D;AAG3D,MAAM,iBAAiB,GAAG,6BAA6B,CAAC;AAExD,SAAS,gBAAgB,CAAC,IAAU,EAAE,OAAe;;IACnD,MAAM,WAAW,GAAG,IAAA,cAAK,EAAC,OAAO,CAAC,OAAO,CAAC,CAAC,QAAQ,CAAC;IAEpD,MAAM,MAAM,GAAG,IAAI,CAAC,IAAI,CAAC,iBAAiB,CAAC,CAAC,QAAQ,EAAE,CAAC;IACvD,MAAM,EAAE,KAAK,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACrC,MAAM,cAAc,GAAG,CAAA,MAAA,MAAA,KAAK,CAAC,CAAC,CAAC,0CAAE,QAAQ,0CAAE,SAAS,KAAI,EAAE,CAAC;IAE3D,MAAM,SAAS,GAAG,yBAAyB,CAAC;IAC5C,MAAM,aAAa,GAAa,MAAA,MAAA,KAAK,CAAC,CAAC,CAAC,0CAAE,QAAQ,0CAC9C,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EACjE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC,CAAC;IAE7C,MAAM,QAAQ,GAAG,4BAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;IACrF,MAAM,UAAU,GAAG,CAAA,aAAa,aAAb,aAAa,uBAAb,aAAa,CAAG,QAAQ,CAAC,KAAI,EAAE,CAAC;IAEnD,uCACK,OAAO,KACV,WAAW;QACX,cAAc;QACd,UAAU,IACV;AACJ,CAAC;AAED,mBAA+B,IAAU,EAAE,OAAe;;QACxD,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,iBAAiB,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,GAAG,CAAC,mEAAmE,CAAC,CAAC;YACjF,OAAO;QACT,CAAC;QAED,MAAM,iBAAiB,GAAG,gBAAgB,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;QAC1D,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,wCAAwC,OAAO,CAAC,GAAG,IAAI,CAAC,CAAC;YACrE,OAAO;QACT,CAAC;QAED,MAAM,MAAM,GAAG,IAAA,iCAAwB,EAAC,IAAI,EAAE,OAAO,CAAC,OAAO,CAAC,CAAC;QAC/D,MAAM,EAAE,WAAW,EAAE,UAAU,EAAE,GAAG,iBAAiB,CAAC;QAEtD,MAAM,CAAC,OAAO,mCACT,MAAM,CAAC,OAAO,KACjB,CAAC,YAAY,OAAO,CAAC,GAAG,EAAE,CAAC,EAAE;gBAC3B,QAAQ,EAAE,iBAAiB;gBAC3B,OAAO,EAAE;oBACP,QAAQ,EAAE;wBACR,kCAAkC,WAAW,OAAO,UAAU,qBAAqB;qBACpF;iBACF;aACF,GACF,CAAC;QAEF,IAAA,mCAA0B,EAAC,IAAI,EAAE,OAAO,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;QAC1D,MAAM,IAAA,oBAAW,EAAC,IAAI,CAAC,CAAC;IAC1B,CAAC;CAAA"}
@@ -0,0 +1,100 @@
1
+ import {
2
+ addProjectConfiguration,
3
+ readProjectConfiguration,
4
+ } from '@nx/devkit';
5
+ import { createTreeWithEmptyWorkspace } from '@nx/devkit/testing';
6
+ import pipeline from '../pipeline/pipeline';
7
+ import generator from './teardown';
8
+ import { Schema } from './schema';
9
+
10
+ describe('Teardown Generator', () => {
11
+ const options: Schema = {
12
+ project: 'test',
13
+ env: 'dev',
14
+ };
15
+
16
+ async function setup(host, envs = 'test-dev test-test test-prod') {
17
+ await pipeline(host, {
18
+ pipeline: 'test',
19
+ registry: 'ghcr.io/test-org',
20
+ type: 'jenkins',
21
+ infra: 'test-infra',
22
+ envs,
23
+ });
24
+ addProjectConfiguration(host, 'test', {
25
+ root: 'apps/test',
26
+ projectType: 'application',
27
+ targets: {
28
+ build: { executor: '@nx/webpack:webpack', options: { compiler: 'tsc', target: 'node' } },
29
+ },
30
+ });
31
+ }
32
+
33
+ it('adds teardown-dev target for dev environment', async () => {
34
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
35
+ await setup(host);
36
+
37
+ await generator(host, options);
38
+
39
+ const config = readProjectConfiguration(host, 'test');
40
+ expect(config.targets['teardown-dev']).toBeTruthy();
41
+ const cmds: string[] = config.targets['teardown-dev'].options.commands;
42
+ expect(cmds.some((c) => c.includes('oc delete'))).toBeTruthy();
43
+ expect(cmds.some((c) => c.includes('test-dev'))).toBeTruthy();
44
+ expect(cmds.some((c) => c.includes('--ignore-not-found'))).toBeTruthy();
45
+ });
46
+
47
+ it('adds teardown-prod target for prod environment', async () => {
48
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
49
+ await setup(host);
50
+
51
+ await generator(host, { ...options, env: 'prod' });
52
+
53
+ const config = readProjectConfiguration(host, 'test');
54
+ expect(config.targets['teardown-prod']).toBeTruthy();
55
+ const cmds: string[] = config.targets['teardown-prod'].options.commands;
56
+ expect(cmds.some((c) => c.includes('test-prod'))).toBeTruthy();
57
+ });
58
+
59
+ it('teardown targets for multiple environments are additive', async () => {
60
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
61
+ await setup(host);
62
+
63
+ await generator(host, { ...options, env: 'dev' });
64
+ await generator(host, { ...options, env: 'test' });
65
+ await generator(host, { ...options, env: 'prod' });
66
+
67
+ const config = readProjectConfiguration(host, 'test');
68
+ expect(config.targets['teardown-dev']).toBeTruthy();
69
+ expect(config.targets['teardown-test']).toBeTruthy();
70
+ expect(config.targets['teardown-prod']).toBeTruthy();
71
+ });
72
+
73
+ it('skips gracefully when environments.yml does not exist', async () => {
74
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
75
+ addProjectConfiguration(host, 'test', {
76
+ root: 'apps/test',
77
+ projectType: 'application',
78
+ targets: {
79
+ build: { executor: '@nx/webpack:webpack', options: { compiler: 'tsc', target: 'node' } },
80
+ },
81
+ });
82
+
83
+ await generator(host, options);
84
+
85
+ const config = readProjectConfiguration(host, 'test');
86
+ expect(config.targets['teardown-dev']).toBeFalsy();
87
+ });
88
+
89
+ it('uses label selector with project name in delete command', async () => {
90
+ const host = createTreeWithEmptyWorkspace({ layout: 'apps-libs' });
91
+ await setup(host);
92
+
93
+ await generator(host, options);
94
+
95
+ const config = readProjectConfiguration(host, 'test');
96
+ const cmds: string[] = config.targets['teardown-dev'].options.commands;
97
+ expect(cmds.some((c) => c.includes('-l app=test'))).toBeTruthy();
98
+ expect(cmds.some((c) => c.includes('all,configmap'))).toBeTruthy();
99
+ });
100
+ });