@red-hat-developer-hub/e2e-test-utils 1.1.24 → 1.1.26

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.
@@ -0,0 +1,563 @@
1
+ /**
2
+ * Realistic workspace fixture tests — based on actual workspace configurations.
3
+ * Each test simulates a real workspace's dynamic-plugins.yaml pattern.
4
+ */
5
+ /* eslint-disable @typescript-eslint/naming-convention -- test fixtures use real plugin config keys with dots/dashes */
6
+ import { describe, it, beforeEach, afterEach } from "node:test";
7
+ import assert from "node:assert";
8
+ import fs from "fs-extra";
9
+ import { processPluginsForDeployment, generatePluginsFromMetadata, } from "../plugin-metadata.js";
10
+ import { withCleanEnv, createMetadataFixture } from "./helpers.js";
11
+ describe("processPluginsForDeployment — workspace fixtures", () => {
12
+ const env = withCleanEnv();
13
+ beforeEach(() => env.save());
14
+ afterEach(() => env.restore());
15
+ // ── argocd-like ─────────────────────────────────────────────────────────
16
+ describe("argocd-like workspace (OCI with aliases + local kubernetes)", () => {
17
+ it("resolves OCI plugins to metadata refs and keeps local plugins unchanged", async () => {
18
+ delete process.env.GIT_PR_NUMBER;
19
+ delete process.env.E2E_NIGHTLY_MODE;
20
+ const metadataDir = await createMetadataFixture([
21
+ {
22
+ name: "backstage-community-plugin-argocd",
23
+ packageName: "@backstage-community/plugin-argocd",
24
+ dynamicArtifact: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd:bs_1.45.3__2.4.3!backstage-community-plugin-argocd",
25
+ appConfigExamples: {
26
+ dynamicPlugins: {
27
+ frontend: {
28
+ "backstage-community.plugin-argocd": {
29
+ mountPoints: [
30
+ {
31
+ mountPoint: "entity.page.cd/cards",
32
+ importName: "EntityArgocdContent",
33
+ },
34
+ ],
35
+ },
36
+ },
37
+ },
38
+ },
39
+ },
40
+ {
41
+ name: "backstage-community-plugin-argocd-backend",
42
+ packageName: "@backstage-community/plugin-argocd-backend",
43
+ dynamicArtifact: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd-backend:bs_1.45.3__1.0.2!backstage-community-plugin-argocd-backend",
44
+ },
45
+ ]);
46
+ try {
47
+ const config = {
48
+ plugins: [
49
+ {
50
+ package: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd:old__tag!backstage-community-plugin-argocd",
51
+ disabled: false,
52
+ pluginConfig: {
53
+ dynamicPlugins: {
54
+ frontend: {
55
+ "backstage-community.plugin-argocd": {
56
+ mountPoints: [
57
+ {
58
+ mountPoint: "entity.page.cd/cards",
59
+ importName: "CustomArgoContent",
60
+ },
61
+ ],
62
+ },
63
+ },
64
+ },
65
+ },
66
+ },
67
+ {
68
+ package: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd-backend:old__tag!backstage-community-plugin-argocd-backend",
69
+ disabled: false,
70
+ },
71
+ {
72
+ package: "./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic",
73
+ disabled: false,
74
+ },
75
+ {
76
+ package: "./dynamic-plugins/dist/backstage-plugin-kubernetes",
77
+ disabled: false,
78
+ },
79
+ ],
80
+ };
81
+ const result = await processPluginsForDeployment(config, metadataDir);
82
+ const plugins = result.plugins;
83
+ assert.strictEqual(plugins.length, 4, "must preserve all 4 plugins");
84
+ // OCI argocd frontend → metadata ref
85
+ assert.ok(plugins[0].package.includes("bs_1.45.3__2.4.3"), "argocd frontend OCI must resolve to metadata version");
86
+ // User pluginConfig overrides metadata
87
+ const frontendConfig = plugins[0].pluginConfig?.dynamicPlugins;
88
+ const frontend = frontendConfig?.frontend;
89
+ const argoMount = frontend?.["backstage-community.plugin-argocd"];
90
+ const mounts = argoMount?.mountPoints;
91
+ assert.strictEqual(mounts?.[0]?.importName, "CustomArgoContent", "user pluginConfig must override metadata mountPoints");
92
+ // OCI argocd backend → metadata ref
93
+ assert.ok(plugins[1].package.includes("bs_1.45.3__1.0.2"), "argocd backend OCI must resolve to metadata version");
94
+ // Cross-workspace kubernetes plugins (no metadata) → unchanged
95
+ assert.strictEqual(plugins[2].package, "./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic", "cross-workspace local plugin must stay unchanged");
96
+ assert.strictEqual(plugins[3].package, "./dynamic-plugins/dist/backstage-plugin-kubernetes", "cross-workspace local plugin must stay unchanged");
97
+ }
98
+ finally {
99
+ await fs.remove(metadataDir);
100
+ }
101
+ });
102
+ });
103
+ // ── scorecard-like ──────────────────────────────────────────────────────
104
+ describe("scorecard-like workspace (disabled plugin + cross-workspace OCI)", () => {
105
+ it("preserves disabled flag and handles cross-workspace OCI plugin", async () => {
106
+ delete process.env.GIT_PR_NUMBER;
107
+ delete process.env.E2E_NIGHTLY_MODE;
108
+ const metadataDir = await createMetadataFixture([
109
+ {
110
+ name: "rhdh-backstage-plugin-scorecard",
111
+ packageName: "@red-hat-developer-hub/backstage-plugin-scorecard",
112
+ dynamicArtifact: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard:bs_1.45.3__2.3.5!red-hat-developer-hub-backstage-plugin-scorecard",
113
+ },
114
+ ]);
115
+ try {
116
+ const config = {
117
+ plugins: [
118
+ {
119
+ package: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-scorecard:old_tag!red-hat-developer-hub-backstage-plugin-scorecard",
120
+ disabled: false,
121
+ pluginConfig: { dynamicPlugins: { frontend: {} } },
122
+ },
123
+ {
124
+ package: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-dynamic-home-page:bs_1.45.3__1.10.3!red-hat-developer-hub-backstage-plugin-dynamic-home-page",
125
+ disabled: false,
126
+ },
127
+ {
128
+ package: "./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page",
129
+ disabled: true,
130
+ },
131
+ ],
132
+ };
133
+ const result = await processPluginsForDeployment(config, metadataDir);
134
+ const plugins = result.plugins;
135
+ assert.strictEqual(plugins.length, 3, "must preserve all 3 plugins");
136
+ assert.ok(plugins[0].package.includes("bs_1.45.3__2.3.5"), "scorecard must resolve to metadata ref");
137
+ assert.ok(plugins[1].package.includes("bs_1.45.3__1.10.3"), "cross-workspace OCI plugin must keep original tag");
138
+ assert.strictEqual(plugins[2].disabled, true, "disabled flag must be preserved");
139
+ assert.strictEqual(plugins[2].package, "./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-dynamic-home-page", "disabled local path must stay unchanged");
140
+ }
141
+ finally {
142
+ await fs.remove(metadataDir);
143
+ }
144
+ });
145
+ });
146
+ // ── github-events-like ──────────────────────────────────────────────────
147
+ describe("github-events-like workspace (OCI without aliases + different registries)", () => {
148
+ it("resolves each OCI to correct metadata registry in nightly", async () => {
149
+ delete process.env.GIT_PR_NUMBER;
150
+ process.env.E2E_NIGHTLY_MODE = "true";
151
+ const metadataDir = await createMetadataFixture([
152
+ {
153
+ name: "backstage-plugin-events-backend-module-github",
154
+ packageName: "@backstage/plugin-events-backend-module-github",
155
+ dynamicArtifact: "oci://quay.io/rhdh/backstage-plugin-events-backend-module-github@sha256:c1d17d47aaa",
156
+ },
157
+ {
158
+ name: "backstage-plugin-catalog-backend-module-github-dynamic",
159
+ packageName: "@backstage/plugin-catalog-backend-module-github",
160
+ dynamicArtifact: "./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic",
161
+ },
162
+ ]);
163
+ try {
164
+ const config = {
165
+ plugins: [
166
+ {
167
+ package: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-events-backend-module-github:bs_1.45.3__0.4.6",
168
+ disabled: false,
169
+ pluginConfig: {
170
+ events: { http: { topics: ["github"] } },
171
+ },
172
+ },
173
+ {
174
+ package: "./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic",
175
+ disabled: false,
176
+ pluginConfig: {
177
+ catalog: { providers: { github: { org: "janus-qe" } } },
178
+ },
179
+ },
180
+ ],
181
+ };
182
+ const result = await processPluginsForDeployment(config, metadataDir);
183
+ const plugins = result.plugins;
184
+ assert.ok(plugins[0].package.startsWith("oci://quay.io/rhdh/"), "must use quay.io registry from metadata, not the ghcr.io from user config");
185
+ assert.ok(plugins[0].package.includes("@sha256:c1d17d47aaa"), "must preserve digest from metadata");
186
+ assert.deepStrictEqual(plugins[0].pluginConfig, { events: { http: { topics: ["github"] } } }, "nightly must preserve user pluginConfig without metadata injection");
187
+ assert.strictEqual(plugins[1].package, "./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic", "local path from metadata must stay unchanged");
188
+ assert.deepStrictEqual(plugins[1].pluginConfig, { catalog: { providers: { github: { org: "janus-qe" } } } }, "nightly must preserve user pluginConfig for local path plugin");
189
+ }
190
+ finally {
191
+ await fs.remove(metadataDir);
192
+ }
193
+ });
194
+ });
195
+ // ── topology-like ───────────────────────────────────────────────────────
196
+ describe("topology-like workspace (all local paths, no OCI)", () => {
197
+ it("keeps all local plugins unchanged in both PR and nightly modes", async () => {
198
+ const metadataDir = await createMetadataFixture([
199
+ {
200
+ name: "backstage-community-plugin-topology",
201
+ packageName: "@backstage-community/plugin-topology",
202
+ dynamicArtifact: "./dynamic-plugins/dist/backstage-community-plugin-topology",
203
+ appConfigExamples: {
204
+ dynamicPlugins: {
205
+ frontend: {
206
+ "backstage-community.plugin-topology": {
207
+ mountPoints: [{ mountPoint: "entity.page.topology/cards" }],
208
+ },
209
+ },
210
+ },
211
+ },
212
+ },
213
+ ]);
214
+ try {
215
+ const config = {
216
+ plugins: [
217
+ {
218
+ package: "./dynamic-plugins/dist/backstage-community-plugin-topology",
219
+ disabled: false,
220
+ },
221
+ {
222
+ package: "./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic",
223
+ disabled: false,
224
+ },
225
+ {
226
+ package: "./dynamic-plugins/dist/backstage-plugin-kubernetes",
227
+ disabled: false,
228
+ },
229
+ ],
230
+ };
231
+ // PR mode
232
+ delete process.env.GIT_PR_NUMBER;
233
+ delete process.env.E2E_NIGHTLY_MODE;
234
+ const prResult = await processPluginsForDeployment(config, metadataDir);
235
+ assert.ok(prResult.plugins[0].pluginConfig, "PR mode must inject pluginConfig for topology");
236
+ assert.strictEqual(prResult.plugins[0].package, "./dynamic-plugins/dist/backstage-community-plugin-topology", "local path must stay unchanged in PR mode");
237
+ // Nightly mode
238
+ process.env.E2E_NIGHTLY_MODE = "true";
239
+ const nightlyResult = await processPluginsForDeployment({ ...config, plugins: config.plugins.map((p) => ({ ...p })) }, metadataDir);
240
+ assert.strictEqual(nightlyResult.plugins[0].pluginConfig, undefined, "nightly must not inject pluginConfig");
241
+ for (const result of [prResult, nightlyResult]) {
242
+ for (const plugin of result.plugins) {
243
+ assert.ok(plugin.package.startsWith("./dynamic-plugins/dist/"), `all plugins must stay as local paths, got: ${plugin.package}`);
244
+ }
245
+ }
246
+ }
247
+ finally {
248
+ await fs.remove(metadataDir);
249
+ }
250
+ });
251
+ });
252
+ // ── global-header-like ──────────────────────────────────────────────────
253
+ describe("global-header-like workspace (npm package passthrough)", () => {
254
+ it("keeps npm package references with integrity unchanged", async () => {
255
+ delete process.env.GIT_PR_NUMBER;
256
+ delete process.env.E2E_NIGHTLY_MODE;
257
+ const metadataDir = await createMetadataFixture([]);
258
+ try {
259
+ const npmPackage = "@red-hat-developer-hub/backstage-plugin-global-header-test@0.0.2";
260
+ const config = {
261
+ plugins: [
262
+ {
263
+ package: npmPackage,
264
+ disabled: false,
265
+ integrity: "sha512-ABC123...",
266
+ pluginConfig: { dynamicPlugins: { frontend: {} } },
267
+ },
268
+ {
269
+ package: "./dynamic-plugins/dist/red-hat-developer-hub-backstage-plugin-global-header",
270
+ disabled: false,
271
+ },
272
+ ],
273
+ };
274
+ const result = await processPluginsForDeployment(config, metadataDir);
275
+ assert.strictEqual(result.plugins[0].package, npmPackage, "npm package reference must pass through unchanged");
276
+ assert.strictEqual(result.plugins[0].integrity, "sha512-ABC123...", "integrity hash must be preserved");
277
+ }
278
+ finally {
279
+ await fs.remove(metadataDir);
280
+ }
281
+ });
282
+ });
283
+ // ── tech-radar-like (auto-generate) ─────────────────────────────────────
284
+ describe("auto-generate from metadata (tech-radar-like, no user config)", () => {
285
+ it("generates correct entries from metadata with mixed artifact types", async () => {
286
+ const metadataDir = await createMetadataFixture([
287
+ {
288
+ name: "backstage-community-plugin-tech-radar",
289
+ packageName: "@backstage-community/plugin-tech-radar",
290
+ dynamicArtifact: "./dynamic-plugins/dist/backstage-community-plugin-tech-radar",
291
+ appConfigExamples: {
292
+ techRadar: { url: "http://example.com/tech-radar" },
293
+ },
294
+ },
295
+ {
296
+ name: "backstage-community-plugin-tech-radar-backend-dynamic",
297
+ packageName: "@backstage-community/plugin-tech-radar-backend",
298
+ dynamicArtifact: "./dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic",
299
+ },
300
+ ]);
301
+ try {
302
+ const generated = await generatePluginsFromMetadata(metadataDir);
303
+ assert.strictEqual(generated.plugins.length, 2, "must generate 2 entries");
304
+ for (const plugin of generated.plugins) {
305
+ assert.strictEqual(plugin.disabled, false, "generated plugins must be enabled");
306
+ assert.strictEqual(plugin.pluginConfig, undefined, "generated plugins must NOT include pluginConfig");
307
+ }
308
+ const packages = generated.plugins.map((p) => p.package).sort();
309
+ assert.ok(packages.includes("./dynamic-plugins/dist/backstage-community-plugin-tech-radar"), "must include tech-radar frontend");
310
+ assert.ok(packages.includes("./dynamic-plugins/dist/backstage-community-plugin-tech-radar-backend-dynamic"), "must include tech-radar backend");
311
+ }
312
+ finally {
313
+ await fs.remove(metadataDir);
314
+ }
315
+ });
316
+ });
317
+ // ── orchestrator-like ───────────────────────────────────────────────────
318
+ describe("registry.access.redhat.com plugins (orchestrator-like)", () => {
319
+ it("resolves to registry.access.redhat.com from metadata", async () => {
320
+ delete process.env.GIT_PR_NUMBER;
321
+ delete process.env.E2E_NIGHTLY_MODE;
322
+ const metadataDir = await createMetadataFixture([
323
+ {
324
+ name: "redhat-backstage-plugin-orchestrator",
325
+ packageName: "@redhat/backstage-plugin-orchestrator",
326
+ dynamicArtifact: "oci://registry.access.redhat.com/rhdh/red-hat-developer-hub-backstage-plugin-orchestrator@sha256:f40d39fb7599",
327
+ },
328
+ ]);
329
+ try {
330
+ const config = {
331
+ plugins: [
332
+ {
333
+ package: "oci://ghcr.io/some/other/red-hat-developer-hub-backstage-plugin-orchestrator:some_tag",
334
+ disabled: false,
335
+ },
336
+ ],
337
+ };
338
+ const result = await processPluginsForDeployment(config, metadataDir);
339
+ assert.ok(result.plugins[0].package.startsWith("oci://registry.access.redhat.com/rhdh/"), "must use registry.access.redhat.com from metadata");
340
+ assert.ok(result.plugins[0].package.includes("@sha256:f40d39fb7599"), "must preserve digest from metadata");
341
+ }
342
+ finally {
343
+ await fs.remove(metadataDir);
344
+ }
345
+ });
346
+ });
347
+ // ── Edge cases ──────────────────────────────────────────────────────────
348
+ describe("edge cases", () => {
349
+ it("returns config as-is when plugins array is undefined", async () => {
350
+ const config = { includes: ["dynamic-plugins.default.yaml"] };
351
+ const result = await processPluginsForDeployment(config);
352
+ assert.deepStrictEqual(result, config);
353
+ });
354
+ it("handles empty plugins array", async () => {
355
+ const metadataDir = await createMetadataFixture([]);
356
+ try {
357
+ const config = { plugins: [] };
358
+ const result = await processPluginsForDeployment(config, metadataDir);
359
+ assert.strictEqual(result.plugins.length, 0);
360
+ }
361
+ finally {
362
+ await fs.remove(metadataDir);
363
+ }
364
+ });
365
+ it("preserves includes and other top-level fields", async () => {
366
+ const metadataDir = await createMetadataFixture([]);
367
+ try {
368
+ const config = {
369
+ includes: ["dynamic-plugins.default.yaml"],
370
+ plugins: [],
371
+ };
372
+ const result = await processPluginsForDeployment(config, metadataDir);
373
+ assert.deepStrictEqual(result.includes, [
374
+ "dynamic-plugins.default.yaml",
375
+ ]);
376
+ }
377
+ finally {
378
+ await fs.remove(metadataDir);
379
+ }
380
+ });
381
+ it("preserves extra fields on plugin entries (integrity, custom keys)", async () => {
382
+ const metadataDir = await createMetadataFixture([]);
383
+ try {
384
+ const config = {
385
+ plugins: [
386
+ {
387
+ package: "./dynamic-plugins/dist/some-plugin",
388
+ disabled: false,
389
+ integrity: "sha512-hash",
390
+ customField: "value",
391
+ },
392
+ ],
393
+ };
394
+ const result = await processPluginsForDeployment(config, metadataDir);
395
+ assert.strictEqual(result.plugins[0].integrity, "sha512-hash");
396
+ assert.strictEqual(result.plugins[0].customField, "value");
397
+ }
398
+ finally {
399
+ await fs.remove(metadataDir);
400
+ }
401
+ });
402
+ it("does not inject pluginConfig for plugins with no appConfigExamples", async () => {
403
+ delete process.env.GIT_PR_NUMBER;
404
+ delete process.env.E2E_NIGHTLY_MODE;
405
+ const metadataDir = await createMetadataFixture([
406
+ {
407
+ name: "backstage-plugin-kubernetes-backend-dynamic",
408
+ packageName: "@backstage/plugin-kubernetes-backend",
409
+ dynamicArtifact: "./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic",
410
+ },
411
+ ]);
412
+ try {
413
+ const config = {
414
+ plugins: [
415
+ {
416
+ package: "./dynamic-plugins/dist/backstage-plugin-kubernetes-backend-dynamic",
417
+ disabled: false,
418
+ },
419
+ ],
420
+ };
421
+ const result = await processPluginsForDeployment(config, metadataDir);
422
+ const pc = result.plugins[0].pluginConfig;
423
+ if (pc) {
424
+ assert.deepStrictEqual(pc, {}, "plugins without appConfigExamples must get empty pluginConfig or undefined");
425
+ }
426
+ }
427
+ finally {
428
+ await fs.remove(metadataDir);
429
+ }
430
+ });
431
+ it("deep merges nested pluginConfig (metadata base + user partial override)", async () => {
432
+ delete process.env.GIT_PR_NUMBER;
433
+ delete process.env.E2E_NIGHTLY_MODE;
434
+ const metadataDir = await createMetadataFixture([
435
+ {
436
+ name: "backstage-community-plugin-argocd",
437
+ packageName: "@backstage-community/plugin-argocd",
438
+ dynamicArtifact: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd:bs_1.45.3__2.4.3!backstage-community-plugin-argocd",
439
+ appConfigExamples: {
440
+ dynamicPlugins: {
441
+ frontend: {
442
+ "backstage-community.plugin-argocd": {
443
+ mountPoints: [
444
+ {
445
+ mountPoint: "entity.page.cd/cards",
446
+ importName: "ArgoContent",
447
+ },
448
+ ],
449
+ entityTabs: [{ path: "/cd", title: "CD" }],
450
+ },
451
+ },
452
+ },
453
+ },
454
+ },
455
+ ]);
456
+ try {
457
+ const config = {
458
+ plugins: [
459
+ {
460
+ package: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-argocd:old!backstage-community-plugin-argocd",
461
+ disabled: false,
462
+ pluginConfig: {
463
+ dynamicPlugins: {
464
+ frontend: {
465
+ "backstage-community.plugin-argocd": {
466
+ mountPoints: [
467
+ {
468
+ mountPoint: "entity.page.cd/cards",
469
+ importName: "CustomArgo",
470
+ },
471
+ ],
472
+ },
473
+ },
474
+ },
475
+ },
476
+ },
477
+ ],
478
+ };
479
+ const result = await processPluginsForDeployment(config, metadataDir);
480
+ const pc = result.plugins[0].pluginConfig;
481
+ const dp = pc?.dynamicPlugins;
482
+ const fe = dp?.frontend;
483
+ const argoConfig = fe?.["backstage-community.plugin-argocd"];
484
+ const mounts = argoConfig?.mountPoints;
485
+ assert.strictEqual(mounts?.[0]?.importName, "CustomArgo", "user mountPoints must override metadata mountPoints");
486
+ const tabs = argoConfig?.entityTabs;
487
+ assert.ok(tabs, "entityTabs from metadata must be preserved when user doesn't override");
488
+ assert.strictEqual(tabs?.[0]?.path, "/cd", "entityTabs must come from metadata base");
489
+ }
490
+ finally {
491
+ await fs.remove(metadataDir);
492
+ }
493
+ });
494
+ it("handles non-existent metadata directory gracefully", async () => {
495
+ delete process.env.GIT_PR_NUMBER;
496
+ delete process.env.E2E_NIGHTLY_MODE;
497
+ const config = {
498
+ plugins: [
499
+ {
500
+ package: "./dynamic-plugins/dist/some-plugin",
501
+ disabled: false,
502
+ pluginConfig: { key: "value" },
503
+ },
504
+ ],
505
+ };
506
+ const result = await processPluginsForDeployment(config, "/tmp/nonexistent-metadata-dir-12345");
507
+ assert.strictEqual(result.plugins[0].package, "./dynamic-plugins/dist/some-plugin", "plugin must pass through when metadata dir doesn't exist");
508
+ assert.deepStrictEqual(result.plugins[0].pluginConfig, { key: "value" }, "pluginConfig must be preserved when metadata dir doesn't exist");
509
+ });
510
+ it("config has local path but metadata has OCI artifact for same plugin", async () => {
511
+ delete process.env.GIT_PR_NUMBER;
512
+ delete process.env.E2E_NIGHTLY_MODE;
513
+ const metadataDir = await createMetadataFixture([
514
+ {
515
+ name: "backstage-community-plugin-tekton",
516
+ packageName: "@backstage-community/plugin-tekton",
517
+ dynamicArtifact: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-tekton:bs_1.45.3__3.33.3!backstage-community-plugin-tekton",
518
+ },
519
+ ]);
520
+ try {
521
+ const config = {
522
+ plugins: [
523
+ {
524
+ package: "./dynamic-plugins/dist/backstage-community-plugin-tekton",
525
+ disabled: false,
526
+ },
527
+ ],
528
+ };
529
+ const result = await processPluginsForDeployment(config, metadataDir);
530
+ assert.ok(result.plugins[0].package.startsWith("oci://"), "local path in config must be resolved to OCI when metadata has OCI dynamicArtifact");
531
+ }
532
+ finally {
533
+ await fs.remove(metadataDir);
534
+ }
535
+ });
536
+ it("shared OCI image with alias (redhat-resource-optimization pattern)", async () => {
537
+ delete process.env.GIT_PR_NUMBER;
538
+ delete process.env.E2E_NIGHTLY_MODE;
539
+ const metadataDir = await createMetadataFixture([
540
+ {
541
+ name: "redhat-resource-optimization",
542
+ packageName: "@red-hat-developer-hub/plugin-redhat-resource-optimization",
543
+ dynamicArtifact: "oci://quay.io/redhat-resource-optimization/dynamic-plugins:1.3.2!red-hat-developer-hub-plugin-redhat-resource-optimization",
544
+ },
545
+ ]);
546
+ try {
547
+ const config = {
548
+ plugins: [
549
+ {
550
+ package: "oci://quay.io/redhat-resource-optimization/dynamic-plugins:old_tag!red-hat-developer-hub-plugin-redhat-resource-optimization",
551
+ disabled: false,
552
+ },
553
+ ],
554
+ };
555
+ const result = await processPluginsForDeployment(config, metadataDir);
556
+ assert.strictEqual(result.plugins[0].package, "oci://quay.io/redhat-resource-optimization/dynamic-plugins:1.3.2!red-hat-developer-hub-plugin-redhat-resource-optimization", "shared OCI image must resolve to metadata version with alias preserved");
557
+ }
558
+ finally {
559
+ await fs.remove(metadataDir);
560
+ }
561
+ });
562
+ });
563
+ });
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=plugin-metadata.nightly.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plugin-metadata.nightly.test.d.ts","sourceRoot":"","sources":["../../../src/utils/tests/plugin-metadata.nightly.test.ts"],"names":[],"mappings":""}