diff --git a/docs/api/deployment/deployment-types.md b/docs/api/deployment/deployment-types.md index 68fccb1..b417af2 100644 --- a/docs/api/deployment/deployment-types.md +++ b/docs/api/deployment/deployment-types.md @@ -42,6 +42,8 @@ type DeploymentOptions = { method?: DeploymentMethod; valueFile?: string; subscription?: string; + disableWrappers?: string[]; + useNewFrontendSystem?: boolean; }; ``` @@ -56,6 +58,8 @@ type DeploymentOptions = { | `method` | `DeploymentMethod` | Installation method | | `valueFile` | `string` | Helm values file (Helm only) | | `subscription` | `string` | Backstage CR file (Operator only) | +| `disableWrappers` | `string[]` | Wrapper plugins to disable (PR builds) | +| `useNewFrontendSystem` | `boolean` | New frontend system (app-next / NFS shell); see [RHDH deployment](/guide/deployment/rhdh-deployment#new-frontend-system-usenewfrontendsystem) | ## DeploymentConfigBase @@ -67,6 +71,8 @@ type DeploymentConfigBase = { appConfig: string; secrets: string; dynamicPlugins: string; + disableWrappers: string[]; + useNewFrontendSystem: boolean; }; ``` diff --git a/docs/changelog.md b/docs/changelog.md index c315905..a1acfe6 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -2,7 +2,13 @@ All notable changes to this project will be documented in this file. -## [1.1.37] - Current +## [1.1.38] - Current + +### Added + +- **`useNewFrontendSystem`** — Optional flag on `rhdh.configure()` for Backstage **app-next** / new frontend system tests: merges `APP_CONFIG_app_packageName` and `ENABLE_STANDARD_MODULE_FEDERATION` into `rhdh-secrets`, adds default OCI dynamic plugins for **app-auth** and **app-integrations**, optional Helm merge layers (`value_file.new-frontend.yaml`, workspace `tests/config/value_file-app-next.yaml`). Env overrides: `RHDH_E2E_NFS_APP_AUTH_PACKAGE`, `RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE` (full `oci://` refs). Exported constants `RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV` and `RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV`. Types re-exported from `@red-hat-developer-hub/e2e-test-utils/rhdh`. + +## [1.1.37] ### Added diff --git a/docs/guide/configuration/config-files.md b/docs/guide/configuration/config-files.md index ca5c61f..bec5fd0 100644 --- a/docs/guide/configuration/config-files.md +++ b/docs/guide/configuration/config-files.md @@ -46,6 +46,10 @@ catalog: Configure dynamic plugins: +::: tip `useNewFrontendSystem` +If you run against the **app-next** shell, set `useNewFrontendSystem: true` on [`configure()`](/guide/deployment/rhdh-deployment#new-frontend-system-usenewfrontendsystem) so the package merges default **app-auth** and **app-integrations** OCI plugins (and optional [env overrides](/guide/configuration/environment-variables#new-frontend-system-app-next-shell-plugins)). You can then omit those entries from this file when the defaults match your train. +::: + ```yaml includes: - dynamic-plugins.default.yaml diff --git a/docs/guide/configuration/environment-variables.md b/docs/guide/configuration/environment-variables.md index 7079ef0..b316f54 100644 --- a/docs/guide/configuration/environment-variables.md +++ b/docs/guide/configuration/environment-variables.md @@ -48,6 +48,19 @@ These control automatic plugin configuration injection from metadata files: | `JOB_NAME` | CI job name (set by OpenShift CI/Prow) | If contains `periodic-`, injection is disabled | | `JOB_MODE` | CI-only: `nightly` or `pr-check` (set by step registry) | Informational | +## New frontend system (app-next shell plugins) + +When [`useNewFrontendSystem`](/guide/deployment/rhdh-deployment#new-frontend-system-usenewfrontendsystem) is `true`, the package adds default OCI packages for **app-auth** and **app-integrations**. You can override each with a **full** `oci://` reference (optional): + +| Variable | Description | Default | +|----------|-------------|---------| +| `RHDH_E2E_NFS_APP_AUTH_PACKAGE` | Full `oci://` package ref for `red-hat-developer-hub-backstage-plugin-app-auth` | Baked default in package YAML | +| `RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE` | Full `oci://` package ref for `red-hat-developer-hub-backstage-plugin-app-integrations` | Baked default in package YAML | + +If an env var is **unset**, the default ref from the package is used. If set, it **replaces** that plugin entry (useful in CI to pin versions without publishing a new `@red-hat-developer-hub/e2e-test-utils` release). + +Constants matching these names are exported as `RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV` and `RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV` from `@red-hat-developer-hub/e2e-test-utils/rhdh`. + ### OCI URL Generation When `GIT_PR_NUMBER` is set, the package replaces local plugin paths with OCI URLs: diff --git a/docs/guide/configuration/index.md b/docs/guide/configuration/index.md index a95c389..7dadf73 100644 --- a/docs/guide/configuration/index.md +++ b/docs/guide/configuration/index.md @@ -9,7 +9,7 @@ The package provides configuration tools for ESLint, TypeScript, and RHDH deploy | [Configuration Files](/guide/configuration/config-files) | YAML configuration structure | | [ESLint Configuration](/guide/configuration/eslint-config) | Pre-configured ESLint rules | | [TypeScript Configuration](/guide/configuration/typescript-config) | Base TypeScript settings | -| [Environment Variables](/guide/configuration/environment-variables) | All environment variables | +| [Environment Variables](/guide/configuration/environment-variables) | All environment variables (including NFS / app-next shell plugin overrides) | | [Disabling Conflicting Wrappers](/guide/configuration/disable-wrappers) | Disabling pre-enabled wrappers that may cause configuration conflicts | ## Project Configuration @@ -69,6 +69,8 @@ RHDH configurations are merged in layers: This allows you to override only what you need while using sensible defaults. +For tests targeting the **new frontend system** (app-next), see [`useNewFrontendSystem`](/guide/deployment/rhdh-deployment#new-frontend-system-usenewfrontendsystem) on `configure()` and [NFS-related environment variables](/guide/configuration/environment-variables#new-frontend-system-app-next-shell-plugins). + ## Plugin Metadata Injection For PR builds, the package can automatically inject plugin configurations from metadata files. See [Plugin Metadata Injection](/guide/configuration/config-files#plugin-metadata-injection) for details. diff --git a/docs/guide/deployment/rhdh-deployment.md b/docs/guide/deployment/rhdh-deployment.md index 985152e..a818416 100644 --- a/docs/guide/deployment/rhdh-deployment.md +++ b/docs/guide/deployment/rhdh-deployment.md @@ -57,6 +57,30 @@ test("example", async ({ rhdh }) => { | `dynamicPlugins` | `string` | Path to dynamic-plugins YAML | | `valueFile` | `string` | Helm values file (Helm only) | | `subscription` | `string` | Backstage CR file (Operator only) | +| `disableWrappers` | `string[]` | Wrapper plugin package names to disable (`GIT_PR_NUMBER` flows) | +| `useNewFrontendSystem` | `boolean` | When `true`, enables the Backstage **new frontend system** shell (app-next): merges `APP_CONFIG_app_packageName` / `ENABLE_STANDARD_MODULE_FEDERATION` into `rhdh-secrets`, adds OCI **app-auth** and **app-integrations** dynamic plugins (with optional env overrides — see [Environment Variables](/guide/configuration/environment-variables#new-frontend-system-app-next-shell-plugins)), and merges extra Helm values (`value_file.new-frontend.yaml`, optional workspace `tests/config/value_file-app-next.yaml`). Defaults to `false`. | + +### New frontend system (`useNewFrontendSystem`) + +Set `useNewFrontendSystem: true` in **`configure()`** when tests must run against the **app-next** frontend (often called NFS in docs). Typical flow: + +```typescript +await rhdh.configure({ + auth: "keycloak", + useNewFrontendSystem: true, +}); +await rhdh.deploy(); +``` + +Do **not** rely on the worker fixture’s argument-free `configure()` call for this flag — pass it in `beforeAll` with the rest of your deployment options **before** `deploy()`, as you do for `auth` and custom config paths. + +What gets merged: + +1. **Secrets** — `APP_CONFIG_app_packageName: app-next` and `ENABLE_STANDARD_MODULE_FEDERATION: "true"` (workspace `rhdh-secrets.yaml` still supplies plugin-specific secrets). +2. **Dynamic plugins** — Default OCI refs for `red-hat-developer-hub-backstage-plugin-app-auth` and `...-app-integrations`, overridable via `RHDH_E2E_NFS_APP_AUTH_PACKAGE` and `RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE` (full `oci://` URIs). +3. **Helm** — Package merge layer `config/helm/value_file.new-frontend.yaml` (shipped with the package), then your `value_file.yaml`, then optional `tests/config/value_file-app-next.yaml` when that file exists. + +Workspace-specific **app-config** (titles, plugin routes, etc.) remains your responsibility. ### Example: Full Configuration @@ -114,12 +138,13 @@ await rhdh.deploy({ timeout: null }); This method: 1. Merges configuration files (common → auth → project) -2. [Injects plugin metadata](/guide/configuration/config-files#plugin-metadata-injection) into dynamic plugins config -3. Applies ConfigMaps (app-config, dynamic-plugins) -4. Applies Secrets (with environment variable substitution) -5. Installs RHDH via Helm or Operator -6. Waits for the deployment to be ready -7. Sets `RHDH_BASE_URL` environment variable +2. Optionally applies **new frontend system** merges when [`useNewFrontendSystem`](#deploymentoptions) was set on `configure()` (secrets, optional OCI shell plugins, Helm layers) +3. [Injects plugin metadata](/guide/configuration/config-files#plugin-metadata-injection) into dynamic plugins config +4. Applies ConfigMaps (app-config, dynamic-plugins) +5. Applies Secrets (with environment variable substitution) +6. Installs RHDH via Helm or Operator +7. Waits for the deployment to be ready +8. Sets `RHDH_BASE_URL` environment variable #### Base URL format diff --git a/docs/overlay/reference/environment-variables.md b/docs/overlay/reference/environment-variables.md index aac9ef6..f604376 100644 --- a/docs/overlay/reference/environment-variables.md +++ b/docs/overlay/reference/environment-variables.md @@ -42,6 +42,17 @@ See [Running Locally - Secrets from Vault](/overlay/tutorials/running-locally#se | `INSTALLATION_METHOD` | Deployment method: `helm` or `operator` | `helm` | No | | `CHART_URL` | Custom Helm chart URL | `oci://quay.io/rhdh/chart` | No | +### New frontend system (optional OCI overrides) + +Used when tests call `configure({ useNewFrontendSystem: true })`. Same semantics as the [guide environment reference](/guide/configuration/environment-variables#new-frontend-system-app-next-shell-plugins): full `oci://` refs; unset keeps package defaults. + +| Variable | Description | +|----------|-------------| +| `RHDH_E2E_NFS_APP_AUTH_PACKAGE` | Override default OCI ref for app-auth | +| `RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE` | Override default OCI ref for app-integrations | + +Set these in Vault or CI job env when you need to pin shell plugin versions per pipeline. + ### Cluster Configuration | Variable | Description | Default | Required | diff --git a/docs/overlay/test-structure/configuration-files.md b/docs/overlay/test-structure/configuration-files.md index 0282212..584c5bc 100644 --- a/docs/overlay/test-structure/configuration-files.md +++ b/docs/overlay/test-structure/configuration-files.md @@ -27,11 +27,23 @@ tests/config/ ├── rhdh-secrets.yaml # Kubernetes secrets (optional) ├── dynamic-plugins.yaml # Dynamic plugins (optional - usually not needed) ├── value_file.yaml # Helm values override (optional, Helm only) +├── value_file-app-next.yaml # Extra Helm values when useNewFrontendSystem is true (optional) └── subscription.yaml # Operator subscription (optional, Operator only) ``` **All of these files are optional.** Only create them when you need to override or extend defaults. +## `useNewFrontendSystem` (app-next / NFS) + +When you pass `useNewFrontendSystem: true` to [`configure()`](/guide/deployment/rhdh-deployment#configureoptions), `@red-hat-developer-hub/e2e-test-utils` merges: + +- **Secrets** — `APP_CONFIG_app_packageName=app-next` and `ENABLE_STANDARD_MODULE_FEDERATION=true` into the `rhdh-secrets` Secret (you no longer need duplicate keys in a separate `rhdh-secrets-next.yaml` for that). +- **Dynamic plugins** — Default OCI entries for **app-auth** and **app-integrations**, overridable via `RHDH_E2E_NFS_APP_AUTH_PACKAGE` / `RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE` ([guide](/guide/configuration/environment-variables#new-frontend-system-app-next-shell-plugins)). + +You can **remove** hand-maintained `app-auth` / `app-integrations` lines from `dynamic-plugins.yaml` when the framework supplies them. Keep workspace-only plugins and metadata-driven config as today. + +Optional **`value_file-app-next.yaml`** is merged last when `useNewFrontendSystem` is true and the file exists — use for chart tweaks specific to app-next runs. + ## app-config-rhdh.yaml (Optional) The main RHDH configuration file. This file is merged with default configurations from `@red-hat-developer-hub/e2e-test-utils`. diff --git a/package.json b/package.json index 5cbe6f9..f5d563b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@red-hat-developer-hub/e2e-test-utils", - "version": "1.1.37", + "version": "1.1.38", "description": "Test utilities for RHDH E2E tests", "license": "Apache-2.0", "repository": { diff --git a/src/deployment/rhdh/config/common/new-frontend-system-dynamic-plugins.yaml b/src/deployment/rhdh/config/common/new-frontend-system-dynamic-plugins.yaml new file mode 100644 index 0000000..e02f4fe --- /dev/null +++ b/src/deployment/rhdh/config/common/new-frontend-system-dynamic-plugins.yaml @@ -0,0 +1,7 @@ +includes: + - dynamic-plugins.default.yaml +plugins: + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-app-auth:bs_1.49.4__0.0.1 + disabled: false + - package: oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-app-integrations:bs_1.49.4__0.0.1 + disabled: false diff --git a/src/deployment/rhdh/config/common/new-frontend-system-secrets.yaml b/src/deployment/rhdh/config/common/new-frontend-system-secrets.yaml new file mode 100644 index 0000000..b8ba0f6 --- /dev/null +++ b/src/deployment/rhdh/config/common/new-frontend-system-secrets.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: Secret +metadata: + name: rhdh-secrets +type: Opaque +stringData: + APP_CONFIG_app_packageName: app-next + ENABLE_STANDARD_MODULE_FEDERATION: "true" diff --git a/src/deployment/rhdh/config/helm/value_file.new-frontend.yaml b/src/deployment/rhdh/config/helm/value_file.new-frontend.yaml new file mode 100644 index 0000000..4616a27 --- /dev/null +++ b/src/deployment/rhdh/config/helm/value_file.new-frontend.yaml @@ -0,0 +1,2 @@ +# Helm values merge layer when useNewFrontendSystem is true (additive; extend as needed). +{} diff --git a/src/deployment/rhdh/constants.ts b/src/deployment/rhdh/constants.ts index 9d70ac4..ed0cbf0 100644 --- a/src/deployment/rhdh/constants.ts +++ b/src/deployment/rhdh/constants.ts @@ -18,11 +18,26 @@ export const DEFAULT_CONFIG_PATHS = { PACKAGE_ROOT, "dist/deployment/rhdh/config/common/dynamic-plugins.yaml", ), + /** New frontend system (app-next): merged when useNewFrontendSystem is true */ + newFrontendSystem: { + secrets: path.join( + PACKAGE_ROOT, + "dist/deployment/rhdh/config/common/new-frontend-system-secrets.yaml", + ), + dynamicPlugins: path.join( + PACKAGE_ROOT, + "dist/deployment/rhdh/config/common/new-frontend-system-dynamic-plugins.yaml", + ), + }, helm: { valueFile: path.join( PACKAGE_ROOT, "dist/deployment/rhdh/config/helm/value_file.yaml", ), + valueFileNewFrontend: path.join( + PACKAGE_ROOT, + "dist/deployment/rhdh/config/helm/value_file.new-frontend.yaml", + ), }, operator: { subscription: path.join( diff --git a/src/deployment/rhdh/deployment.test.ts b/src/deployment/rhdh/deployment.test.ts index 19b1521..0663688 100644 --- a/src/deployment/rhdh/deployment.test.ts +++ b/src/deployment/rhdh/deployment.test.ts @@ -49,4 +49,38 @@ describe("dynamic-plugins merge (no user config path)", () => { "metadata (OCI) must win over auth local path", ); }); + + it("dedupes NFS shell plugin against duplicate OCI ref for same logical plugin", () => { + const userPlugins: Record = { + plugins: [ + { + package: + "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-app-auth:older__0.0.1", + disabled: false, + }, + ], + }; + const nfsMerge: Record = { + plugins: [ + { + package: + "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/red-hat-developer-hub-backstage-plugin-app-auth:bs_1.49.4__0.0.1", + disabled: false, + }, + ], + }; + const merged = deepMerge(userPlugins, nfsMerge, { + arrayMergeStrategy: { + byKey: "package", + normalizeKey: (item) => + getNormalizedPluginMergeKey(item as Record), + }, + }); + const plugins = merged.plugins as Array<{ package?: string }>; + assert.strictEqual(plugins.length, 1); + assert.ok( + plugins[0].package?.includes("bs_1.49.4__0.0.1"), + "NFS fragment should merge into same logical plugin entry", + ); + }); }); diff --git a/src/deployment/rhdh/deployment.ts b/src/deployment/rhdh/deployment.ts index 9f8093c..1f8faf5 100644 --- a/src/deployment/rhdh/deployment.ts +++ b/src/deployment/rhdh/deployment.ts @@ -22,6 +22,7 @@ import { AUTH_CONFIG_PATHS, CHART_URL, } from "./constants.js"; +import { loadNewFrontendShellPlugins } from "./new-frontend-system-plugins.js"; import type { DeploymentOptions, DeploymentConfig, @@ -114,9 +115,17 @@ export class RHDHDeployment { if (typeof value === "string") return envsubst(value); }); + let secretPayload = substituted as Record; + if (this.deploymentConfig.useNewFrontendSystem) { + const nfsSecrets = await mergeYamlFilesIfExists([ + DEFAULT_CONFIG_PATHS.newFrontendSystem.secrets, + ]); + secretPayload = deepMerge(secretPayload, nfsSecrets); + } + await this.k8sClient.applySecretFromObject( "rhdh-secrets", - substituted as { stringData?: Record }, + secretPayload as { stringData?: Record }, this.deploymentConfig.namespace, ); } @@ -192,6 +201,20 @@ export class RHDHDeployment { config = await this._mergeGeneratedWithBase(generated); } + if (this.deploymentConfig.useNewFrontendSystem) { + const nfsPlugins = loadNewFrontendShellPlugins() as Record< + string, + unknown + >; + config = deepMerge(config, nfsPlugins, { + arrayMergeStrategy: { + byKey: "package", + normalizeKey: (item) => + getNormalizedPluginMergeKey(item as Record), + }, + }); + } + // Process for deployment: inject metadata (PR only) + resolve all packages to OCI let result = await processPluginsForDeployment( config as DynamicPluginsConfig, @@ -224,10 +247,20 @@ export class RHDHDeployment { this.deploymentConfig.version, ); this._log(`Helm chart version resolved to: ${chartVersion}`); - const valueFileObject = (await mergeYamlFilesIfExists([ + const helmValuePaths = [ DEFAULT_CONFIG_PATHS.helm.valueFile, + ...(this.deploymentConfig.useNewFrontendSystem + ? [DEFAULT_CONFIG_PATHS.helm.valueFileNewFrontend] + : []), valueFile, - ])) as Record>; + ...(this.deploymentConfig.useNewFrontendSystem && + fs.existsSync(WorkspacePaths.valueFileAppNext) + ? [WorkspacePaths.valueFileAppNext] + : []), + ]; + const valueFileObject = (await mergeYamlFilesIfExists( + helmValuePaths, + )) as Record>; this._logBoxen("Value File", valueFileObject); @@ -513,6 +546,7 @@ export class RHDHDeployment { secrets: input.secrets ?? WorkspacePaths.secrets, dynamicPlugins: input.dynamicPlugins ?? WorkspacePaths.dynamicPlugins, disableWrappers: input.disableWrappers ?? [], + useNewFrontendSystem: input.useNewFrontendSystem ?? false, }; if (method === "helm") { diff --git a/src/deployment/rhdh/index.ts b/src/deployment/rhdh/index.ts index 8e83699..48bed57 100644 --- a/src/deployment/rhdh/index.ts +++ b/src/deployment/rhdh/index.ts @@ -1 +1,6 @@ export { RHDHDeployment } from "./deployment.js"; +export { + RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV, + RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV, +} from "./new-frontend-system-plugins.js"; +export * from "./types.js"; diff --git a/src/deployment/rhdh/new-frontend-system-plugins.test.ts b/src/deployment/rhdh/new-frontend-system-plugins.test.ts new file mode 100644 index 0000000..f3f2522 --- /dev/null +++ b/src/deployment/rhdh/new-frontend-system-plugins.test.ts @@ -0,0 +1,56 @@ +import { describe, it, beforeEach, afterEach } from "node:test"; +import assert from "node:assert"; +import { + loadNewFrontendShellPlugins, + RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV, + RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV, +} from "./new-frontend-system-plugins.js"; + +describe("loadNewFrontendShellPlugins", () => { + let savedAuth: string | undefined; + let savedInteg: string | undefined; + + beforeEach(() => { + savedAuth = process.env[RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV]; + savedInteg = process.env[RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV]; + delete process.env[RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV]; + delete process.env[RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV]; + }); + + afterEach(() => { + if (savedAuth === undefined) + delete process.env[RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV]; + else process.env[RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV] = savedAuth; + + if (savedInteg === undefined) + delete process.env[RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV]; + else process.env[RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV] = savedInteg; + }); + + it("loads default OCI refs when env overrides are unset", () => { + const c = loadNewFrontendShellPlugins(); + assert.strictEqual(c.plugins?.length, 2); + assert.ok(c.plugins?.[0].package?.includes("app-auth")); + assert.ok(c.plugins?.[1].package?.includes("app-integrations")); + assert.ok(c.plugins?.[0].package?.includes("bs_1.49.4__0.0.1")); + assert.ok(c.plugins?.[1].package?.includes("bs_1.49.4__0.0.1")); + }); + + it("prefers env full-URI overrides over defaults", () => { + process.env[RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV] = + "oci://example.test/ns/red-hat-developer-hub-backstage-plugin-app-auth:override"; + process.env[RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV] = + "oci://example.test/ns/red-hat-developer-hub-backstage-plugin-app-integrations:override"; + + const c = loadNewFrontendShellPlugins(); + + assert.strictEqual( + c.plugins?.[0].package, + "oci://example.test/ns/red-hat-developer-hub-backstage-plugin-app-auth:override", + ); + assert.strictEqual( + c.plugins?.[1].package, + "oci://example.test/ns/red-hat-developer-hub-backstage-plugin-app-integrations:override", + ); + }); +}); diff --git a/src/deployment/rhdh/new-frontend-system-plugins.ts b/src/deployment/rhdh/new-frontend-system-plugins.ts new file mode 100644 index 0000000..452db46 --- /dev/null +++ b/src/deployment/rhdh/new-frontend-system-plugins.ts @@ -0,0 +1,53 @@ +import fs from "fs-extra"; +import yaml from "js-yaml"; +import { DEFAULT_CONFIG_PATHS } from "./constants.js"; +import { + extractPluginName, + type DynamicPluginsConfig, +} from "../../utils/plugin-metadata.js"; + +/** Env: full `oci://` package ref for app-auth when using useNewFrontendSystem (overrides default). */ +export const RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV = + "RHDH_E2E_NFS_APP_AUTH_PACKAGE" as const; + +/** Env: full `oci://` package ref for app-integrations when using useNewFrontendSystem (overrides default). */ +export const RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV = + "RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE" as const; + +const LOGICAL_APP_AUTH = "red-hat-developer-hub-backstage-plugin-app-auth"; +const LOGICAL_APP_INTEGRATIONS = + "red-hat-developer-hub-backstage-plugin-app-integrations"; + +/** + * Loads the package default NFS shell plugin list and applies optional env overrides. + */ +export function loadNewFrontendShellPlugins(): DynamicPluginsConfig { + const raw = fs.readFileSync( + DEFAULT_CONFIG_PATHS.newFrontendSystem.dynamicPlugins, + "utf8", + ); + const config = yaml.load(raw) as DynamicPluginsConfig; + + const authOverride = process.env[RHDH_E2E_NFS_APP_AUTH_PACKAGE_ENV]; + const integrationsOverride = + process.env[RHDH_E2E_NFS_APP_INTEGRATIONS_PACKAGE_ENV]; + + if (!config.plugins?.length) { + return config; + } + + for (const plugin of config.plugins) { + const pkg = plugin.package; + if (!pkg) continue; + const logical = extractPluginName(pkg); + + if (logical === LOGICAL_APP_AUTH && authOverride) { + plugin.package = authOverride; + } + if (logical === LOGICAL_APP_INTEGRATIONS && integrationsOverride) { + plugin.package = integrationsOverride; + } + } + + return config; +} diff --git a/src/deployment/rhdh/types.ts b/src/deployment/rhdh/types.ts index 7e42b79..8aa6114 100644 --- a/src/deployment/rhdh/types.ts +++ b/src/deployment/rhdh/types.ts @@ -12,6 +12,8 @@ export type DeploymentOptions = { valueFile?: string; subscription?: string; disableWrappers?: string[]; + /** When true, merge app-next shell env, OCI app-auth/app-integrations plugins, and optional Helm layers. */ + useNewFrontendSystem?: boolean; }; export type HelmDeploymentConfig = { @@ -32,6 +34,8 @@ export type DeploymentConfigBase = { secrets: string; dynamicPlugins: string; disableWrappers: string[]; + /** New frontend system (Backstage app-next / NFS shell). */ + useNewFrontendSystem: boolean; }; export type DeploymentConfig = DeploymentConfigBase & diff --git a/src/utils/workspace-paths.ts b/src/utils/workspace-paths.ts index 286ae67..e7f4738 100644 --- a/src/utils/workspace-paths.ts +++ b/src/utils/workspace-paths.ts @@ -70,6 +70,14 @@ export class WorkspacePaths { return path.resolve(this.e2eRoot, "tests/config/value_file.yaml"); } + /** + * Optional Helm values when `useNewFrontendSystem` is true (`rhdh.configure()`). + * Merged after the workspace `value_file.yaml` when this file exists. + */ + static get valueFileAppNext(): string { + return path.resolve(this.e2eRoot, "tests/config/value_file-app-next.yaml"); + } + /** Default operator subscription path: `tests/config/subscription.yaml` */ static get subscription(): string { return path.resolve(this.e2eRoot, "tests/config/subscription.yaml");