From 8ec61b2473e075832f00598c6905055e13abcaee Mon Sep 17 00:00:00 2001 From: Stan Lewis Date: Tue, 5 May 2026 07:59:58 -0400 Subject: [PATCH] feat(deployment): Add new frontend system option This change adds a useNewFrontendSystem option to configure the RHDH deployment to load the new frontend system app-next package instead of the old frontend system app package. This change also adds the relevant plugins in this mode that are required for logging in using other authentication providers than the guest login as well as source control authentication support. Tests that want to use the new frontend system simply need to set useNewFrontendSystem to "true" in the options object for rhdh.configure(). Assisted-By: Cursor Desktop rh-pre-commit.version: 2.3.2 rh-pre-commit.check-secrets: ENABLED --- docs/api/deployment/deployment-types.md | 6 ++ docs/changelog.md | 8 ++- docs/guide/configuration/config-files.md | 4 ++ .../configuration/environment-variables.md | 13 +++++ docs/guide/configuration/index.md | 4 +- docs/guide/deployment/rhdh-deployment.md | 37 ++++++++++-- .../reference/environment-variables.md | 11 ++++ .../test-structure/configuration-files.md | 12 ++++ package.json | 2 +- .../new-frontend-system-dynamic-plugins.yaml | 7 +++ .../common/new-frontend-system-secrets.yaml | 8 +++ .../config/helm/value_file.new-frontend.yaml | 2 + src/deployment/rhdh/constants.ts | 15 +++++ src/deployment/rhdh/deployment.test.ts | 34 +++++++++++ src/deployment/rhdh/deployment.ts | 40 ++++++++++++- src/deployment/rhdh/index.ts | 5 ++ .../rhdh/new-frontend-system-plugins.test.ts | 56 +++++++++++++++++++ .../rhdh/new-frontend-system-plugins.ts | 53 ++++++++++++++++++ src/deployment/rhdh/types.ts | 4 ++ src/utils/workspace-paths.ts | 8 +++ 20 files changed, 317 insertions(+), 12 deletions(-) create mode 100644 src/deployment/rhdh/config/common/new-frontend-system-dynamic-plugins.yaml create mode 100644 src/deployment/rhdh/config/common/new-frontend-system-secrets.yaml create mode 100644 src/deployment/rhdh/config/helm/value_file.new-frontend.yaml create mode 100644 src/deployment/rhdh/new-frontend-system-plugins.test.ts create mode 100644 src/deployment/rhdh/new-frontend-system-plugins.ts 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");