@red-hat-developer-hub/e2e-test-utils 1.1.10
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/LICENSE +201 -0
- package/README.md +6 -0
- package/dist/deployment/keycloak/config/keycloak-values.yaml +96 -0
- package/dist/deployment/keycloak/constants.d.ts +29 -0
- package/dist/deployment/keycloak/constants.d.ts.map +1 -0
- package/dist/deployment/keycloak/constants.js +75 -0
- package/dist/deployment/keycloak/deployment.d.ts +89 -0
- package/dist/deployment/keycloak/deployment.d.ts.map +1 -0
- package/dist/deployment/keycloak/deployment.js +435 -0
- package/dist/deployment/keycloak/index.d.ts +2 -0
- package/dist/deployment/keycloak/index.d.ts.map +1 -0
- package/dist/deployment/keycloak/index.js +1 -0
- package/dist/deployment/keycloak/types.d.ts +59 -0
- package/dist/deployment/keycloak/types.d.ts.map +1 -0
- package/dist/deployment/keycloak/types.js +1 -0
- package/dist/deployment/rhdh/config/auth/guest/app-config.yaml +5 -0
- package/dist/deployment/rhdh/config/auth/keycloak/app-config.yaml +19 -0
- package/dist/deployment/rhdh/config/auth/keycloak/dynamic-plugins.yaml +3 -0
- package/dist/deployment/rhdh/config/auth/keycloak/secrets.yaml +12 -0
- package/dist/deployment/rhdh/config/common/app-config-rhdh.yaml +6 -0
- package/dist/deployment/rhdh/config/common/dynamic-plugins.yaml +3 -0
- package/dist/deployment/rhdh/config/common/rhdh-secrets.yaml +7 -0
- package/dist/deployment/rhdh/config/helm/value_file.yaml +7 -0
- package/dist/deployment/rhdh/config/operator/subscription.yaml +21 -0
- package/dist/deployment/rhdh/constants.d.ts +19 -0
- package/dist/deployment/rhdh/constants.d.ts.map +1 -0
- package/dist/deployment/rhdh/constants.js +27 -0
- package/dist/deployment/rhdh/deployment.d.ts +40 -0
- package/dist/deployment/rhdh/deployment.d.ts.map +1 -0
- package/dist/deployment/rhdh/deployment.js +303 -0
- package/dist/deployment/rhdh/index.d.ts +2 -0
- package/dist/deployment/rhdh/index.d.ts.map +1 -0
- package/dist/deployment/rhdh/index.js +1 -0
- package/dist/deployment/rhdh/types.d.ts +31 -0
- package/dist/deployment/rhdh/types.d.ts.map +1 -0
- package/dist/deployment/rhdh/types.js +1 -0
- package/dist/eslint/base.config.d.ts +10 -0
- package/dist/eslint/base.config.d.ts.map +1 -0
- package/dist/eslint/base.config.js +213 -0
- package/dist/playwright/base-config.d.ts +14 -0
- package/dist/playwright/base-config.d.ts.map +1 -0
- package/dist/playwright/base-config.js +47 -0
- package/dist/playwright/fixtures/test.d.ts +13 -0
- package/dist/playwright/fixtures/test.d.ts.map +1 -0
- package/dist/playwright/fixtures/test.js +48 -0
- package/dist/playwright/global-setup.d.ts +6 -0
- package/dist/playwright/global-setup.d.ts.map +1 -0
- package/dist/playwright/global-setup.js +67 -0
- package/dist/playwright/helpers/accessibility.d.ts +13 -0
- package/dist/playwright/helpers/accessibility.d.ts.map +1 -0
- package/dist/playwright/helpers/accessibility.js +24 -0
- package/dist/playwright/helpers/api-endpoints.d.ts +11 -0
- package/dist/playwright/helpers/api-endpoints.d.ts.map +1 -0
- package/dist/playwright/helpers/api-endpoints.js +15 -0
- package/dist/playwright/helpers/api-helper.d.ts +77 -0
- package/dist/playwright/helpers/api-helper.d.ts.map +1 -0
- package/dist/playwright/helpers/api-helper.js +285 -0
- package/dist/playwright/helpers/common.d.ts +31 -0
- package/dist/playwright/helpers/common.d.ts.map +1 -0
- package/dist/playwright/helpers/common.js +342 -0
- package/dist/playwright/helpers/index.d.ts +5 -0
- package/dist/playwright/helpers/index.d.ts.map +1 -0
- package/dist/playwright/helpers/index.js +4 -0
- package/dist/playwright/helpers/navbar.d.ts +2 -0
- package/dist/playwright/helpers/navbar.d.ts.map +1 -0
- package/dist/playwright/helpers/navbar.js +1 -0
- package/dist/playwright/helpers/ui-helper.d.ts +106 -0
- package/dist/playwright/helpers/ui-helper.d.ts.map +1 -0
- package/dist/playwright/helpers/ui-helper.js +439 -0
- package/dist/playwright/page-objects/global-obj.d.ts +25 -0
- package/dist/playwright/page-objects/global-obj.d.ts.map +1 -0
- package/dist/playwright/page-objects/global-obj.js +24 -0
- package/dist/playwright/page-objects/page-obj.d.ts +41 -0
- package/dist/playwright/page-objects/page-obj.d.ts.map +1 -0
- package/dist/playwright/page-objects/page-obj.js +40 -0
- package/dist/playwright/pages/catalog-import.d.ts +31 -0
- package/dist/playwright/pages/catalog-import.d.ts.map +1 -0
- package/dist/playwright/pages/catalog-import.js +65 -0
- package/dist/playwright/pages/catalog.d.ts +14 -0
- package/dist/playwright/pages/catalog.d.ts.map +1 -0
- package/dist/playwright/pages/catalog.js +37 -0
- package/dist/playwright/pages/extensions.d.ts +38 -0
- package/dist/playwright/pages/extensions.d.ts.map +1 -0
- package/dist/playwright/pages/extensions.js +110 -0
- package/dist/playwright/pages/home-page.d.ts +10 -0
- package/dist/playwright/pages/home-page.d.ts.map +1 -0
- package/dist/playwright/pages/home-page.js +46 -0
- package/dist/playwright/pages/index.d.ts +6 -0
- package/dist/playwright/pages/index.d.ts.map +1 -0
- package/dist/playwright/pages/index.js +5 -0
- package/dist/playwright/pages/notifications.d.ts +24 -0
- package/dist/playwright/pages/notifications.d.ts.map +1 -0
- package/dist/playwright/pages/notifications.js +112 -0
- package/dist/utils/bash.d.ts +3 -0
- package/dist/utils/bash.d.ts.map +1 -0
- package/dist/utils/bash.js +4 -0
- package/dist/utils/common.d.ts +3 -0
- package/dist/utils/common.d.ts.map +1 -0
- package/dist/utils/common.js +8 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +4 -0
- package/dist/utils/kubernetes-client.d.ts +97 -0
- package/dist/utils/kubernetes-client.d.ts.map +1 -0
- package/dist/utils/kubernetes-client.js +558 -0
- package/dist/utils/merge-yamls.d.ts +50 -0
- package/dist/utils/merge-yamls.d.ts.map +1 -0
- package/dist/utils/merge-yamls.js +96 -0
- package/dist/utils/plugin-metadata.d.ts +116 -0
- package/dist/utils/plugin-metadata.d.ts.map +1 -0
- package/dist/utils/plugin-metadata.js +330 -0
- package/package.json +108 -0
- package/tsconfig.base.json +16 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import yaml from "js-yaml";
|
|
3
|
+
import mergeWith from "lodash.mergewith";
|
|
4
|
+
/**
|
|
5
|
+
* Merges two arrays of objects by a specific key.
|
|
6
|
+
* Objects with matching keys are deeply merged, new objects are appended.
|
|
7
|
+
*/
|
|
8
|
+
function mergeArraysByKey(target, source, key, mergeOptions) {
|
|
9
|
+
const result = [...target];
|
|
10
|
+
for (const srcItem of source) {
|
|
11
|
+
if (typeof srcItem === "object" && srcItem !== null && key in srcItem) {
|
|
12
|
+
const srcKeyValue = srcItem[key];
|
|
13
|
+
const existingIndex = result.findIndex((item) => typeof item === "object" &&
|
|
14
|
+
item !== null &&
|
|
15
|
+
item[key] === srcKeyValue);
|
|
16
|
+
if (existingIndex !== -1) {
|
|
17
|
+
// Merge existing object with source object
|
|
18
|
+
result[existingIndex] = deepMerge(result[existingIndex], srcItem, mergeOptions);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
// Append new object
|
|
22
|
+
result.push(srcItem);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
// Non-object or missing key, append as-is
|
|
27
|
+
result.push(srcItem);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Deeply merges two YAML-compatible objects.
|
|
34
|
+
* Array handling is controlled by the arrayMergeStrategy option.
|
|
35
|
+
*/
|
|
36
|
+
export function deepMerge(target, source, options = {}) {
|
|
37
|
+
const strategy = options.arrayMergeStrategy ?? "replace";
|
|
38
|
+
return mergeWith({ ...target }, source, (objValue, srcValue) => {
|
|
39
|
+
if (Array.isArray(objValue) && Array.isArray(srcValue)) {
|
|
40
|
+
if (strategy === "replace") {
|
|
41
|
+
return srcValue;
|
|
42
|
+
}
|
|
43
|
+
else if (strategy === "concat") {
|
|
44
|
+
return [...objValue, ...srcValue];
|
|
45
|
+
}
|
|
46
|
+
else if (typeof strategy === "object" && "byKey" in strategy) {
|
|
47
|
+
return mergeArraysByKey(objValue, srcValue, strategy.byKey, options);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* Merge multiple YAML files into one object.
|
|
54
|
+
*
|
|
55
|
+
* @param paths List of YAML file paths (base first, overlays last)
|
|
56
|
+
* @param options Optional merge options (e.g., arrayMergeStrategy)
|
|
57
|
+
* @returns Merged YAML object
|
|
58
|
+
*/
|
|
59
|
+
export async function mergeYamlFiles(paths, options = {}) {
|
|
60
|
+
let merged = {};
|
|
61
|
+
for (const path of paths) {
|
|
62
|
+
const content = await fs.readFile(path, "utf8");
|
|
63
|
+
const parsed = (yaml.load(content) || {});
|
|
64
|
+
merged = deepMerge(merged, parsed, options);
|
|
65
|
+
}
|
|
66
|
+
return merged;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Merge multiple YAML files if they exist.
|
|
70
|
+
*
|
|
71
|
+
* @param paths List of YAML file paths
|
|
72
|
+
* @param options Optional merge options (e.g., arrayMergeStrategy)
|
|
73
|
+
* @returns Merged YAML object
|
|
74
|
+
*/
|
|
75
|
+
export async function mergeYamlFilesIfExists(paths, options = {}) {
|
|
76
|
+
return await mergeYamlFiles(paths.filter((path) => {
|
|
77
|
+
const exists = fs.existsSync(path);
|
|
78
|
+
if (!exists)
|
|
79
|
+
console.log(`YAML file ${path} does not exist`);
|
|
80
|
+
return exists;
|
|
81
|
+
}), options);
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* Merge multiple YAML files and write the result to an output file.
|
|
85
|
+
*
|
|
86
|
+
* @param inputPaths List of input YAML files
|
|
87
|
+
* @param outputPath Output YAML file path
|
|
88
|
+
* @param dumpOptions Optional dump formatting
|
|
89
|
+
* @param mergeOptions Optional merge options (e.g., arrayMergeStrategy)
|
|
90
|
+
*/
|
|
91
|
+
export async function mergeYamlFilesToFile(inputPaths, outputPath, dumpOptions = { lineWidth: -1 }, mergeOptions = {}) {
|
|
92
|
+
const merged = await mergeYamlFiles(inputPaths, mergeOptions);
|
|
93
|
+
const yamlString = yaml.dump(merged, dumpOptions);
|
|
94
|
+
await fs.outputFile(outputPath, yamlString);
|
|
95
|
+
console.log(`Merged ${inputPaths.length} YAML files into ${outputPath}`);
|
|
96
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Represents parsed plugin metadata from a Package CRD file.
|
|
3
|
+
*/
|
|
4
|
+
export interface PluginMetadata {
|
|
5
|
+
/** The dynamic artifact path (e.g., ./dynamic-plugins/dist/plugin-name) */
|
|
6
|
+
packagePath: string;
|
|
7
|
+
/** The plugin configuration from appConfigExamples[0].content */
|
|
8
|
+
pluginConfig: Record<string, unknown>;
|
|
9
|
+
/** The package name (e.g., @backstage-community/plugin-tech-radar) */
|
|
10
|
+
packageName: string;
|
|
11
|
+
/** Source metadata file path */
|
|
12
|
+
sourceFile: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Checks if plugin metadata handling should be enabled.
|
|
16
|
+
* This controls both auto-generation and injection of plugin metadata.
|
|
17
|
+
*
|
|
18
|
+
* Default: ENABLED (for local dev and PR builds)
|
|
19
|
+
* Disabled when:
|
|
20
|
+
* - RHDH_SKIP_PLUGIN_METADATA_INJECTION is set, OR
|
|
21
|
+
* - JOB_NAME contains "periodic-" (nightly/periodic builds)
|
|
22
|
+
*/
|
|
23
|
+
export declare function shouldInjectPluginMetadata(): boolean;
|
|
24
|
+
/**
|
|
25
|
+
* Extracts the plugin name from a package path or OCI reference.
|
|
26
|
+
*
|
|
27
|
+
* Handles various formats:
|
|
28
|
+
* - Local path: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar
|
|
29
|
+
* - OCI with integrity: oci://quay.io/rhdh/plugin@sha256:...!backstage-community-plugin-tech-radar
|
|
30
|
+
* - OCI without integrity: oci://quay.io/rhdh/backstage-community-plugin-tech-radar:tag
|
|
31
|
+
*
|
|
32
|
+
* @param packageRef The package reference string
|
|
33
|
+
* @returns The extracted plugin name
|
|
34
|
+
*/
|
|
35
|
+
export declare function extractPluginName(packageRef: string): string;
|
|
36
|
+
/**
|
|
37
|
+
* Default metadata directory path relative to the e2e-tests directory.
|
|
38
|
+
* Follows the same pattern as user config paths (e.g., tests/config/dynamic-plugins.yaml).
|
|
39
|
+
*/
|
|
40
|
+
export declare const DEFAULT_METADATA_PATH = "../metadata";
|
|
41
|
+
/**
|
|
42
|
+
* Gets the metadata directory path.
|
|
43
|
+
* Uses the provided path or falls back to DEFAULT_METADATA_PATH.
|
|
44
|
+
*
|
|
45
|
+
* @param metadataPath Optional custom path to metadata directory
|
|
46
|
+
* @returns The metadata directory path, or null if it doesn't exist
|
|
47
|
+
*/
|
|
48
|
+
export declare function getMetadataDirectory(metadataPath?: string): string | null;
|
|
49
|
+
/**
|
|
50
|
+
* Parses a single metadata YAML file and extracts plugin configuration.
|
|
51
|
+
*
|
|
52
|
+
* @param filePath Path to the metadata YAML file
|
|
53
|
+
* @returns PluginMetadata if valid, null otherwise
|
|
54
|
+
*/
|
|
55
|
+
export declare function parseMetadataFile(filePath: string): Promise<PluginMetadata>;
|
|
56
|
+
/**
|
|
57
|
+
* Parses all metadata files in a directory and builds a map of plugin name to config.
|
|
58
|
+
* The plugin name is extracted from the dynamicArtifact path for flexible matching.
|
|
59
|
+
*
|
|
60
|
+
* @param metadataDir Path to the metadata directory
|
|
61
|
+
* @returns Map of plugin name to plugin configuration
|
|
62
|
+
*/
|
|
63
|
+
export declare function parseAllMetadataFiles(metadataDir: string): Promise<Map<string, PluginMetadata>>;
|
|
64
|
+
/**
|
|
65
|
+
* Plugin entry in dynamic-plugins.yaml
|
|
66
|
+
*/
|
|
67
|
+
export interface PluginEntry {
|
|
68
|
+
package: string;
|
|
69
|
+
disabled?: boolean;
|
|
70
|
+
pluginConfig?: Record<string, unknown>;
|
|
71
|
+
[key: string]: unknown;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Dynamic plugins configuration structure
|
|
75
|
+
*/
|
|
76
|
+
export interface DynamicPluginsConfig {
|
|
77
|
+
plugins?: PluginEntry[];
|
|
78
|
+
includes?: string[];
|
|
79
|
+
[key: string]: unknown;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Injects plugin configurations from metadata into a dynamic plugins config.
|
|
83
|
+
* Metadata config serves as the base, user-provided pluginConfig overrides it.
|
|
84
|
+
*
|
|
85
|
+
* Matching is done by extracting the plugin name from both the package reference
|
|
86
|
+
* and the metadata's dynamicArtifact, allowing flexible matching across different
|
|
87
|
+
* package formats (local paths, OCI references, etc.).
|
|
88
|
+
*
|
|
89
|
+
* @param dynamicPluginsConfig The dynamic plugins configuration to augment
|
|
90
|
+
* @param metadataMap Map of plugin names to plugin metadata
|
|
91
|
+
* @returns The augmented configuration with injected pluginConfigs
|
|
92
|
+
*/
|
|
93
|
+
export declare function injectMetadataConfig(dynamicPluginsConfig: DynamicPluginsConfig, metadataMap: Map<string, PluginMetadata>): DynamicPluginsConfig;
|
|
94
|
+
/**
|
|
95
|
+
* Generates a complete dynamic-plugins configuration from metadata files.
|
|
96
|
+
* Iterates through all metadata files and creates plugin entries with:
|
|
97
|
+
* - package: the dynamicArtifact path
|
|
98
|
+
* - disabled: false (enabled by default)
|
|
99
|
+
* - pluginConfig: from appConfigExamples[0].content
|
|
100
|
+
*
|
|
101
|
+
* @param metadataPath Optional custom path to metadata directory (default: ../metadata)
|
|
102
|
+
* @returns Complete dynamic plugins configuration
|
|
103
|
+
* @throws Error if metadata directory not found or no valid metadata files
|
|
104
|
+
*/
|
|
105
|
+
export declare function generateDynamicPluginsConfigFromMetadata(metadataPath?: string): Promise<DynamicPluginsConfig>;
|
|
106
|
+
/**
|
|
107
|
+
* Main function to load and inject plugin metadata for PR builds.
|
|
108
|
+
* For non-PR builds (nightly), returns the config unchanged.
|
|
109
|
+
*
|
|
110
|
+
* @param dynamicPluginsConfig The dynamic plugins configuration
|
|
111
|
+
* @param metadataPath Optional custom path to metadata directory (default: ../metadata)
|
|
112
|
+
* @returns Augmented configuration with metadata (for PR) or unchanged (for nightly)
|
|
113
|
+
* @throws Error if PR build but no metadata directory found
|
|
114
|
+
*/
|
|
115
|
+
export declare function loadAndInjectPluginMetadata(dynamicPluginsConfig: DynamicPluginsConfig, metadataPath?: string): Promise<DynamicPluginsConfig>;
|
|
116
|
+
//# sourceMappingURL=plugin-metadata.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin-metadata.d.ts","sourceRoot":"","sources":["../../src/utils/plugin-metadata.ts"],"names":[],"mappings":"AA8HA;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,2EAA2E;IAC3E,WAAW,EAAE,MAAM,CAAC;IACpB,iEAAiE;IACjE,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,sEAAsE;IACtE,WAAW,EAAE,MAAM,CAAC;IACpB,gCAAgC;IAChC,UAAU,EAAE,MAAM,CAAC;CACpB;AAgBD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAmBpD;AAED;;;;;;;;;;GAUG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAQ5D;AAED;;;GAGG;AACH,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD;;;;;;GAMG;AACH,wBAAgB,oBAAoB,CAClC,YAAY,GAAE,MAA8B,GAC3C,MAAM,GAAG,IAAI,CAUf;AAED;;;;;GAKG;AACH,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CA0BzB;AAED;;;;;;GAMG;AACH,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAwBtC;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED;;GAEG;AACH,MAAM,WAAW,oBAAoB;IACnC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AA4CD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,oBAAoB,EAAE,oBAAoB,EAC1C,WAAW,EAAE,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,GACvC,oBAAoB,CAsCtB;AAED;;;;;;;;;;GAUG;AACH,wBAAsB,wCAAwC,CAC5D,YAAY,GAAE,MAA8B,GAC3C,OAAO,CAAC,oBAAoB,CAAC,CAsD/B;AAED;;;;;;;;GAQG;AACH,wBAAsB,2BAA2B,CAC/C,oBAAoB,EAAE,oBAAoB,EAC1C,YAAY,GAAE,MAA8B,GAC3C,OAAO,CAAC,oBAAoB,CAAC,CAuC/B"}
|
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import fs from "fs-extra";
|
|
2
|
+
import path from "path";
|
|
3
|
+
import yaml from "js-yaml";
|
|
4
|
+
import { glob } from "zx";
|
|
5
|
+
import { deepMerge } from "./merge-yamls.js";
|
|
6
|
+
const OCI_REGISTRY_PREFIX = "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays";
|
|
7
|
+
/**
|
|
8
|
+
* Fetches plugin versions from source repo and builds OCI URL map.
|
|
9
|
+
* Only called when GIT_PR_NUMBER is set.
|
|
10
|
+
*/
|
|
11
|
+
async function getOCIUrlsForPR(workspacePath, prNumber) {
|
|
12
|
+
const ociUrls = new Map();
|
|
13
|
+
const sourceJsonPath = path.join(workspacePath, "source.json");
|
|
14
|
+
const pluginsListPath = path.join(workspacePath, "plugins-list.yaml");
|
|
15
|
+
if (!fs.existsSync(sourceJsonPath)) {
|
|
16
|
+
throw new Error(`[PluginMetadata] PR build requires source.json but not found at: ${sourceJsonPath}`);
|
|
17
|
+
}
|
|
18
|
+
if (!fs.existsSync(pluginsListPath)) {
|
|
19
|
+
throw new Error(`[PluginMetadata] PR build requires plugins-list.yaml but not found at: ${pluginsListPath}`);
|
|
20
|
+
}
|
|
21
|
+
const sourceJson = JSON.parse(await fs.readFile(sourceJsonPath, "utf-8"));
|
|
22
|
+
const { repo, "repo-ref": ref, "repo-flat": repoFlat } = sourceJson;
|
|
23
|
+
if (!repo) {
|
|
24
|
+
throw new Error(`[PluginMetadata] source.json is missing required 'repo' field: ${sourceJsonPath}`);
|
|
25
|
+
}
|
|
26
|
+
if (!ref) {
|
|
27
|
+
throw new Error(`[PluginMetadata] source.json is missing required 'repo-ref' field: ${sourceJsonPath}`);
|
|
28
|
+
}
|
|
29
|
+
// Parse owner/repo from URL
|
|
30
|
+
const match = repo.match(/github\.com\/(.+?)(?:\.git)?$/);
|
|
31
|
+
if (!match) {
|
|
32
|
+
throw new Error(`[PluginMetadata] Failed to parse GitHub repo from source.json: ${repo}`);
|
|
33
|
+
}
|
|
34
|
+
const ownerRepo = match[1];
|
|
35
|
+
// Parse plugins-list.yaml as YAML and extract keys (plugin paths)
|
|
36
|
+
const pluginsListContent = await fs.readFile(pluginsListPath, "utf-8");
|
|
37
|
+
const pluginsListData = yaml.load(pluginsListContent);
|
|
38
|
+
if (!pluginsListData || typeof pluginsListData !== "object") {
|
|
39
|
+
throw new Error(`[PluginMetadata] plugins-list.yaml is empty or invalid: ${pluginsListPath}`);
|
|
40
|
+
}
|
|
41
|
+
const pluginPaths = Object.keys(pluginsListData);
|
|
42
|
+
const workspaceName = path.basename(workspacePath);
|
|
43
|
+
console.log(`[PluginMetadata] Fetching versions for ${pluginPaths.length} plugins from source...`);
|
|
44
|
+
for (const pluginPath of pluginPaths) {
|
|
45
|
+
const pkgJsonPath = repoFlat
|
|
46
|
+
? `${pluginPath}/package.json`
|
|
47
|
+
: `workspaces/${workspaceName}/${pluginPath}/package.json`;
|
|
48
|
+
const rawUrl = `https://raw.githubusercontent.com/${ownerRepo}/${ref}/${pkgJsonPath}`;
|
|
49
|
+
const res = await fetch(rawUrl);
|
|
50
|
+
if (!res.ok) {
|
|
51
|
+
throw new Error(`[PluginMetadata] Failed to fetch package.json for ${pluginPath}: ${res.status} ${res.statusText}\n` +
|
|
52
|
+
` URL: ${rawUrl}`);
|
|
53
|
+
}
|
|
54
|
+
const pkgJson = (await res.json());
|
|
55
|
+
if (!pkgJson.name) {
|
|
56
|
+
throw new Error(`[PluginMetadata] package.json is missing 'name' field for ${pluginPath}\n` +
|
|
57
|
+
` URL: ${rawUrl}`);
|
|
58
|
+
}
|
|
59
|
+
if (!pkgJson.version) {
|
|
60
|
+
throw new Error(`[PluginMetadata] package.json is missing 'version' field for ${pluginPath}\n` +
|
|
61
|
+
` URL: ${rawUrl}`);
|
|
62
|
+
}
|
|
63
|
+
const { name, version } = pkgJson;
|
|
64
|
+
// @backstage-community/plugin-tech-radar -> backstage-community-plugin-tech-radar
|
|
65
|
+
const displayName = name.replace(/^@/, "").replace(/\//g, "-");
|
|
66
|
+
// TODO(RHDHBUGS-2530): Remove !alias suffix once Konflux builds include
|
|
67
|
+
// io.backstage.dynamic-packages annotation. The suffix is a workaround
|
|
68
|
+
// because install-dynamic-plugins.py can't auto-detect plugin path without it.
|
|
69
|
+
const ociUrl = `${OCI_REGISTRY_PREFIX}/${displayName}:pr_${prNumber}__${version}!${displayName}`;
|
|
70
|
+
ociUrls.set(displayName, ociUrl);
|
|
71
|
+
console.log(`[PluginMetadata] ${displayName} -> ${ociUrl}`);
|
|
72
|
+
}
|
|
73
|
+
return ociUrls;
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Checks if plugin metadata handling should be enabled.
|
|
77
|
+
* This controls both auto-generation and injection of plugin metadata.
|
|
78
|
+
*
|
|
79
|
+
* Default: ENABLED (for local dev and PR builds)
|
|
80
|
+
* Disabled when:
|
|
81
|
+
* - RHDH_SKIP_PLUGIN_METADATA_INJECTION is set, OR
|
|
82
|
+
* - JOB_NAME contains "periodic-" (nightly/periodic builds)
|
|
83
|
+
*/
|
|
84
|
+
export function shouldInjectPluginMetadata() {
|
|
85
|
+
// Explicit opt-out
|
|
86
|
+
if (process.env.RHDH_SKIP_PLUGIN_METADATA_INJECTION) {
|
|
87
|
+
console.log("[PluginMetadata] Metadata handling disabled (RHDH_SKIP_PLUGIN_METADATA_INJECTION is set)");
|
|
88
|
+
return false;
|
|
89
|
+
}
|
|
90
|
+
// Periodic/nightly job
|
|
91
|
+
const jobName = process.env.JOB_NAME || "";
|
|
92
|
+
if (jobName.includes("periodic-")) {
|
|
93
|
+
console.log("[PluginMetadata] Metadata handling disabled (periodic job detected)");
|
|
94
|
+
return false;
|
|
95
|
+
}
|
|
96
|
+
return true;
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Extracts the plugin name from a package path or OCI reference.
|
|
100
|
+
*
|
|
101
|
+
* Handles various formats:
|
|
102
|
+
* - Local path: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar
|
|
103
|
+
* - OCI with integrity: oci://quay.io/rhdh/plugin@sha256:...!backstage-community-plugin-tech-radar
|
|
104
|
+
* - OCI without integrity: oci://quay.io/rhdh/backstage-community-plugin-tech-radar:tag
|
|
105
|
+
*
|
|
106
|
+
* @param packageRef The package reference string
|
|
107
|
+
* @returns The extracted plugin name
|
|
108
|
+
*/
|
|
109
|
+
export function extractPluginName(packageRef) {
|
|
110
|
+
// Strip ! suffix if present (e.g., oci://...@sha256:...!alias)
|
|
111
|
+
const ref = packageRef.includes("!") ? packageRef.split("!")[0] : packageRef;
|
|
112
|
+
// Regex to extract plugin name from various formats:
|
|
113
|
+
// Captures the last path segment (chars except / : @) before any :tag or @digest
|
|
114
|
+
const match = ref.match(/\/([^/:@]+)(?:[:@].*)?$/);
|
|
115
|
+
return match?.[1] || packageRef;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Default metadata directory path relative to the e2e-tests directory.
|
|
119
|
+
* Follows the same pattern as user config paths (e.g., tests/config/dynamic-plugins.yaml).
|
|
120
|
+
*/
|
|
121
|
+
export const DEFAULT_METADATA_PATH = "../metadata";
|
|
122
|
+
/**
|
|
123
|
+
* Gets the metadata directory path.
|
|
124
|
+
* Uses the provided path or falls back to DEFAULT_METADATA_PATH.
|
|
125
|
+
*
|
|
126
|
+
* @param metadataPath Optional custom path to metadata directory
|
|
127
|
+
* @returns The metadata directory path, or null if it doesn't exist
|
|
128
|
+
*/
|
|
129
|
+
export function getMetadataDirectory(metadataPath = DEFAULT_METADATA_PATH) {
|
|
130
|
+
const resolvedPath = path.resolve(metadataPath);
|
|
131
|
+
if (fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isDirectory()) {
|
|
132
|
+
console.log(`[PluginMetadata] Using metadata directory: ${resolvedPath}`);
|
|
133
|
+
return resolvedPath;
|
|
134
|
+
}
|
|
135
|
+
console.log(`[PluginMetadata] Metadata directory not found: ${resolvedPath}`);
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
/**
|
|
139
|
+
* Parses a single metadata YAML file and extracts plugin configuration.
|
|
140
|
+
*
|
|
141
|
+
* @param filePath Path to the metadata YAML file
|
|
142
|
+
* @returns PluginMetadata if valid, null otherwise
|
|
143
|
+
*/
|
|
144
|
+
export async function parseMetadataFile(filePath) {
|
|
145
|
+
const content = await fs.readFile(filePath, "utf8");
|
|
146
|
+
const parsed = yaml.load(content);
|
|
147
|
+
const packagePath = parsed?.spec?.dynamicArtifact;
|
|
148
|
+
const packageName = parsed?.spec?.packageName;
|
|
149
|
+
const pluginConfig = parsed?.spec?.appConfigExamples?.[0]?.content;
|
|
150
|
+
if (!packagePath) {
|
|
151
|
+
throw new Error(`[PluginMetadata] Missing required field spec.dynamicArtifact in ${filePath}`);
|
|
152
|
+
}
|
|
153
|
+
if (!packageName) {
|
|
154
|
+
throw new Error(`[PluginMetadata] Missing required field spec.packageName in ${filePath}`);
|
|
155
|
+
}
|
|
156
|
+
return {
|
|
157
|
+
packagePath,
|
|
158
|
+
pluginConfig: pluginConfig || {},
|
|
159
|
+
packageName,
|
|
160
|
+
sourceFile: filePath,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Parses all metadata files in a directory and builds a map of plugin name to config.
|
|
165
|
+
* The plugin name is extracted from the dynamicArtifact path for flexible matching.
|
|
166
|
+
*
|
|
167
|
+
* @param metadataDir Path to the metadata directory
|
|
168
|
+
* @returns Map of plugin name to plugin configuration
|
|
169
|
+
*/
|
|
170
|
+
export async function parseAllMetadataFiles(metadataDir) {
|
|
171
|
+
const pattern = path.join(metadataDir, "*.yaml");
|
|
172
|
+
const files = await glob(pattern);
|
|
173
|
+
console.log(`[PluginMetadata] Found ${files.length} metadata files in ${metadataDir}`);
|
|
174
|
+
const metadataMap = new Map();
|
|
175
|
+
for (const file of files) {
|
|
176
|
+
const metadata = await parseMetadataFile(file);
|
|
177
|
+
const pluginName = extractPluginName(metadata.packagePath);
|
|
178
|
+
metadataMap.set(pluginName, metadata);
|
|
179
|
+
console.log(`[PluginMetadata] Mapped plugin: ${pluginName} <- ${metadata.packagePath}`);
|
|
180
|
+
}
|
|
181
|
+
console.log(`[PluginMetadata] Successfully parsed ${metadataMap.size} plugin metadata entries`);
|
|
182
|
+
return metadataMap;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Replaces local package paths with OCI URLs for plugins that have matching metadata.
|
|
186
|
+
* Only applies to plugins with metadata (workspace plugins). Plugins without metadata
|
|
187
|
+
* (e.g., keycloak, bulk-import from auth defaults) keep their original paths.
|
|
188
|
+
*
|
|
189
|
+
* @param plugins The plugin entries to process
|
|
190
|
+
* @param metadataMap Map of plugin names to plugin metadata
|
|
191
|
+
* @param metadataPath Path to the metadata directory (used to resolve workspace root)
|
|
192
|
+
* @returns Plugin entries with OCI URLs replaced where applicable
|
|
193
|
+
*/
|
|
194
|
+
async function replaceWithOCIUrls(plugins, metadataMap, metadataPath) {
|
|
195
|
+
const prNumber = process.env.GIT_PR_NUMBER;
|
|
196
|
+
if (!prNumber) {
|
|
197
|
+
return plugins;
|
|
198
|
+
}
|
|
199
|
+
console.log(`[PluginMetadata] PR build detected (PR #${prNumber}), fetching OCI URLs...`);
|
|
200
|
+
const workspacePath = path.resolve(metadataPath, "..");
|
|
201
|
+
const ociUrls = await getOCIUrlsForPR(workspacePath, prNumber);
|
|
202
|
+
return plugins.map((plugin) => {
|
|
203
|
+
const pluginName = extractPluginName(plugin.package);
|
|
204
|
+
const metadata = metadataMap.get(pluginName);
|
|
205
|
+
if (!metadata?.packageName)
|
|
206
|
+
return plugin;
|
|
207
|
+
const displayName = metadata.packageName
|
|
208
|
+
.replace(/^@/, "")
|
|
209
|
+
.replace(/\//g, "-");
|
|
210
|
+
const ociUrl = ociUrls.get(displayName);
|
|
211
|
+
if (!ociUrl)
|
|
212
|
+
return plugin;
|
|
213
|
+
console.log(`[PluginMetadata] Replacing ${plugin.package} with ${ociUrl}`);
|
|
214
|
+
return { ...plugin, package: ociUrl };
|
|
215
|
+
});
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Injects plugin configurations from metadata into a dynamic plugins config.
|
|
219
|
+
* Metadata config serves as the base, user-provided pluginConfig overrides it.
|
|
220
|
+
*
|
|
221
|
+
* Matching is done by extracting the plugin name from both the package reference
|
|
222
|
+
* and the metadata's dynamicArtifact, allowing flexible matching across different
|
|
223
|
+
* package formats (local paths, OCI references, etc.).
|
|
224
|
+
*
|
|
225
|
+
* @param dynamicPluginsConfig The dynamic plugins configuration to augment
|
|
226
|
+
* @param metadataMap Map of plugin names to plugin metadata
|
|
227
|
+
* @returns The augmented configuration with injected pluginConfigs
|
|
228
|
+
*/
|
|
229
|
+
export function injectMetadataConfig(dynamicPluginsConfig, metadataMap) {
|
|
230
|
+
if (!dynamicPluginsConfig.plugins) {
|
|
231
|
+
return dynamicPluginsConfig;
|
|
232
|
+
}
|
|
233
|
+
const augmentedPlugins = dynamicPluginsConfig.plugins.map((plugin) => {
|
|
234
|
+
// Extract plugin name from package reference for flexible matching
|
|
235
|
+
const pluginName = extractPluginName(plugin.package);
|
|
236
|
+
const metadata = metadataMap.get(pluginName);
|
|
237
|
+
if (!metadata) {
|
|
238
|
+
// No metadata found for this plugin, keep as-is
|
|
239
|
+
console.log(`[PluginMetadata] No metadata found for: ${pluginName} (from ${plugin.package})`);
|
|
240
|
+
return plugin;
|
|
241
|
+
}
|
|
242
|
+
console.log(`[PluginMetadata] Injecting config for: ${pluginName} (from ${plugin.package})`);
|
|
243
|
+
// Merge: metadata config (base) + user config (override)
|
|
244
|
+
const mergedPluginConfig = deepMerge(metadata.pluginConfig, plugin.pluginConfig || {});
|
|
245
|
+
return {
|
|
246
|
+
...plugin,
|
|
247
|
+
pluginConfig: mergedPluginConfig,
|
|
248
|
+
};
|
|
249
|
+
});
|
|
250
|
+
return {
|
|
251
|
+
...dynamicPluginsConfig,
|
|
252
|
+
plugins: augmentedPlugins,
|
|
253
|
+
};
|
|
254
|
+
}
|
|
255
|
+
/**
|
|
256
|
+
* Generates a complete dynamic-plugins configuration from metadata files.
|
|
257
|
+
* Iterates through all metadata files and creates plugin entries with:
|
|
258
|
+
* - package: the dynamicArtifact path
|
|
259
|
+
* - disabled: false (enabled by default)
|
|
260
|
+
* - pluginConfig: from appConfigExamples[0].content
|
|
261
|
+
*
|
|
262
|
+
* @param metadataPath Optional custom path to metadata directory (default: ../metadata)
|
|
263
|
+
* @returns Complete dynamic plugins configuration
|
|
264
|
+
* @throws Error if metadata directory not found or no valid metadata files
|
|
265
|
+
*/
|
|
266
|
+
export async function generateDynamicPluginsConfigFromMetadata(metadataPath = DEFAULT_METADATA_PATH) {
|
|
267
|
+
// Skip if metadata handling is disabled
|
|
268
|
+
if (!shouldInjectPluginMetadata()) {
|
|
269
|
+
console.log("[PluginMetadata] Returning empty config (metadata handling disabled)");
|
|
270
|
+
return { plugins: [] };
|
|
271
|
+
}
|
|
272
|
+
console.log("[PluginMetadata] No dynamic-plugins config provided, generating from metadata...");
|
|
273
|
+
// Get metadata directory
|
|
274
|
+
const metadataDir = getMetadataDirectory(metadataPath);
|
|
275
|
+
if (!metadataDir) {
|
|
276
|
+
throw new Error(`[PluginMetadata] Cannot generate dynamic-plugins config: metadata directory not found at: ${path.resolve(metadataPath)}`);
|
|
277
|
+
}
|
|
278
|
+
// Parse all metadata files
|
|
279
|
+
const metadataMap = await parseAllMetadataFiles(metadataDir);
|
|
280
|
+
if (metadataMap.size === 0) {
|
|
281
|
+
throw new Error(`[PluginMetadata] Cannot generate dynamic-plugins config: no valid metadata files found in ${metadataDir}`);
|
|
282
|
+
}
|
|
283
|
+
// Build plugin entries from metadata
|
|
284
|
+
let plugins = [];
|
|
285
|
+
for (const [pluginName, metadata] of metadataMap) {
|
|
286
|
+
console.log(`[PluginMetadata] Adding plugin: ${pluginName} (${metadata.packagePath})`);
|
|
287
|
+
plugins.push({
|
|
288
|
+
package: metadata.packagePath,
|
|
289
|
+
disabled: false,
|
|
290
|
+
pluginConfig: metadata.pluginConfig,
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
// Replace local paths with OCI URLs for PR builds
|
|
294
|
+
plugins = await replaceWithOCIUrls(plugins, metadataMap, metadataPath);
|
|
295
|
+
console.log(`[PluginMetadata] Generated dynamic-plugins config with ${plugins.length} plugins`);
|
|
296
|
+
return { plugins };
|
|
297
|
+
}
|
|
298
|
+
/**
|
|
299
|
+
* Main function to load and inject plugin metadata for PR builds.
|
|
300
|
+
* For non-PR builds (nightly), returns the config unchanged.
|
|
301
|
+
*
|
|
302
|
+
* @param dynamicPluginsConfig The dynamic plugins configuration
|
|
303
|
+
* @param metadataPath Optional custom path to metadata directory (default: ../metadata)
|
|
304
|
+
* @returns Augmented configuration with metadata (for PR) or unchanged (for nightly)
|
|
305
|
+
* @throws Error if PR build but no metadata directory found
|
|
306
|
+
*/
|
|
307
|
+
export async function loadAndInjectPluginMetadata(dynamicPluginsConfig, metadataPath = DEFAULT_METADATA_PATH) {
|
|
308
|
+
// Skip metadata injection if disabled
|
|
309
|
+
if (!shouldInjectPluginMetadata()) {
|
|
310
|
+
return dynamicPluginsConfig;
|
|
311
|
+
}
|
|
312
|
+
console.log("[PluginMetadata] Loading plugin metadata...");
|
|
313
|
+
// Get metadata directory
|
|
314
|
+
const metadataDir = getMetadataDirectory(metadataPath);
|
|
315
|
+
if (!metadataDir) {
|
|
316
|
+
throw new Error(`[PluginMetadata] PR build requires metadata directory but not found at: ${path.resolve(metadataPath)}`);
|
|
317
|
+
}
|
|
318
|
+
// Parse all metadata files
|
|
319
|
+
const metadataMap = await parseAllMetadataFiles(metadataDir);
|
|
320
|
+
if (metadataMap.size === 0) {
|
|
321
|
+
throw new Error(`[PluginMetadata] PR build requires plugin metadata but no valid metadata files found in ${metadataDir}`);
|
|
322
|
+
}
|
|
323
|
+
// Inject metadata configs into the dynamic plugins config
|
|
324
|
+
const result = injectMetadataConfig(dynamicPluginsConfig, metadataMap);
|
|
325
|
+
// Replace local paths with OCI URLs for PR builds
|
|
326
|
+
if (result.plugins) {
|
|
327
|
+
result.plugins = await replaceWithOCIUrls(result.plugins, metadataMap, metadataPath);
|
|
328
|
+
}
|
|
329
|
+
return result;
|
|
330
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@red-hat-developer-hub/e2e-test-utils",
|
|
3
|
+
"version": "1.1.10",
|
|
4
|
+
"description": "Test utilities for RHDH E2E tests",
|
|
5
|
+
"license": "Apache-2.0",
|
|
6
|
+
"repository": {
|
|
7
|
+
"type": "git",
|
|
8
|
+
"url": "git+https://github.com/redhat-developer/rhdh-e2e-test-utils.git",
|
|
9
|
+
"directory": "."
|
|
10
|
+
},
|
|
11
|
+
"type": "module",
|
|
12
|
+
"main": "./dist/index.js",
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"exports": {
|
|
15
|
+
"./eslint": {
|
|
16
|
+
"types": "./dist/eslint/base.config.d.ts",
|
|
17
|
+
"default": "./dist/eslint/base.config.js"
|
|
18
|
+
},
|
|
19
|
+
"./test": {
|
|
20
|
+
"types": "./dist/playwright/fixtures/test.d.ts",
|
|
21
|
+
"default": "./dist/playwright/fixtures/test.js"
|
|
22
|
+
},
|
|
23
|
+
"./playwright-config": {
|
|
24
|
+
"types": "./dist/playwright/base-config.d.ts",
|
|
25
|
+
"default": "./dist/playwright/base-config.js"
|
|
26
|
+
},
|
|
27
|
+
"./tsconfig": "./tsconfig.base.json",
|
|
28
|
+
"./rhdh": {
|
|
29
|
+
"types": "./dist/deployment/rhdh/index.d.ts",
|
|
30
|
+
"default": "./dist/deployment/rhdh/index.js"
|
|
31
|
+
},
|
|
32
|
+
"./utils": {
|
|
33
|
+
"types": "./dist/utils/index.d.ts",
|
|
34
|
+
"default": "./dist/utils/index.js"
|
|
35
|
+
},
|
|
36
|
+
"./helpers": {
|
|
37
|
+
"types": "./dist/playwright/helpers/index.d.ts",
|
|
38
|
+
"default": "./dist/playwright/helpers/index.js"
|
|
39
|
+
},
|
|
40
|
+
"./pages": {
|
|
41
|
+
"types": "./dist/playwright/pages/index.d.ts",
|
|
42
|
+
"default": "./dist/playwright/pages/index.js"
|
|
43
|
+
},
|
|
44
|
+
"./keycloak": {
|
|
45
|
+
"types": "./dist/deployment/keycloak/index.d.ts",
|
|
46
|
+
"default": "./dist/deployment/keycloak/index.js"
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
"publishConfig": {
|
|
50
|
+
"access": "public"
|
|
51
|
+
},
|
|
52
|
+
"files": [
|
|
53
|
+
"dist",
|
|
54
|
+
"tsconfig.base.json"
|
|
55
|
+
],
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "yarn clean && tsc -p tsconfig.build.json && cp -r src/deployment/rhdh/config dist/deployment/rhdh/ && cp -r src/deployment/keycloak/config dist/deployment/keycloak/",
|
|
58
|
+
"check": "yarn typecheck && yarn lint:check && yarn prettier:check",
|
|
59
|
+
"clean": "rm -rf dist",
|
|
60
|
+
"lint:check": "eslint . --ignore-pattern dist --ignore-pattern README.md --ignore-pattern docs",
|
|
61
|
+
"lint:fix": "eslint . --fix --ignore-pattern dist --ignore-pattern README.md --ignore-pattern docs",
|
|
62
|
+
"prepublishOnly": "yarn build",
|
|
63
|
+
"prettier:check": "prettier --check . '!dist' '!README.md' '!docs' '!.github/workflows/deploy-docs.yml'",
|
|
64
|
+
"prettier:fix": "prettier --write . '!dist' '!README.md' '!docs' '!.github/workflows/deploy-docs.yml'",
|
|
65
|
+
"typecheck": "tsc --noEmit"
|
|
66
|
+
},
|
|
67
|
+
"keywords": [
|
|
68
|
+
"e2e",
|
|
69
|
+
"playwright",
|
|
70
|
+
"rhdh",
|
|
71
|
+
"test-utils"
|
|
72
|
+
],
|
|
73
|
+
"engines": {
|
|
74
|
+
"node": ">=22",
|
|
75
|
+
"yarn": ">=3"
|
|
76
|
+
},
|
|
77
|
+
"peerDependencies": {
|
|
78
|
+
"@playwright/test": "^1.57.0"
|
|
79
|
+
},
|
|
80
|
+
"devDependencies": {
|
|
81
|
+
"@backstage/catalog-model": "1.7.5",
|
|
82
|
+
"@playwright/test": "^1.57.0",
|
|
83
|
+
"@types/fs-extra": "^11.0.4",
|
|
84
|
+
"@types/js-yaml": "^4.0.9",
|
|
85
|
+
"@types/lodash.clonedeepwith": "^4.5.9",
|
|
86
|
+
"@types/lodash.mergewith": "^4.6.9",
|
|
87
|
+
"@types/node": "^24.10.1"
|
|
88
|
+
},
|
|
89
|
+
"dependencies": {
|
|
90
|
+
"@axe-core/playwright": "^4.11.0",
|
|
91
|
+
"@eslint/js": "^9.39.1",
|
|
92
|
+
"@keycloak/keycloak-admin-client": "^26.0.0",
|
|
93
|
+
"@kubernetes/client-node": "^1.4.0",
|
|
94
|
+
"eslint": "^9.39.1",
|
|
95
|
+
"eslint-plugin-check-file": "^3.3.1",
|
|
96
|
+
"eslint-plugin-playwright": "^2.4.0",
|
|
97
|
+
"fs-extra": "^11.3.2",
|
|
98
|
+
"js-yaml": "^4.1.1",
|
|
99
|
+
"lodash.clonedeepwith": "^4.5.0",
|
|
100
|
+
"lodash.mergewith": "^4.6.2",
|
|
101
|
+
"otplib": "12.0.1",
|
|
102
|
+
"prettier": "^3.7.4",
|
|
103
|
+
"typescript": "^5.9.3",
|
|
104
|
+
"typescript-eslint": "^8.48.1",
|
|
105
|
+
"zx": "^8.8.5"
|
|
106
|
+
},
|
|
107
|
+
"packageManager": "yarn@3.8.7"
|
|
108
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "ES2022",
|
|
4
|
+
"module": "ESNext",
|
|
5
|
+
"moduleResolution": "bundler",
|
|
6
|
+
"lib": ["ES2022"],
|
|
7
|
+
"strict": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"skipLibCheck": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"resolveJsonModule": true,
|
|
12
|
+
"noEmit": true,
|
|
13
|
+
"types": ["node"]
|
|
14
|
+
},
|
|
15
|
+
"exclude": ["node_modules", "test-results", "playwright-report"]
|
|
16
|
+
}
|