@red-hat-developer-hub/e2e-test-utils 1.1.30 → 1.1.32

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.
@@ -105,9 +105,9 @@ log::success() {
105
105
  # Operator subscription and status
106
106
  # ---------------------------------------------------------------------------
107
107
  install_subscription() {
108
- local name=$1 namespace=$2 channel=$3 package=$4 source_name=$5 source_namespace=$6
109
- oc apply -f - << EOD
110
- apiVersion: operators.coreos.com/v1alpha1
108
+ local name=$1 namespace=$2 channel=$3 package=$4 source_name=$5 source_namespace=$6 starting_csv=${7:-}
109
+ local yaml
110
+ yaml="apiVersion: operators.coreos.com/v1alpha1
111
111
  kind: Subscription
112
112
  metadata:
113
113
  name: $name
@@ -117,30 +117,38 @@ spec:
117
117
  installPlanApproval: Automatic
118
118
  name: $package
119
119
  source: $source_name
120
- sourceNamespace: $source_namespace
121
- EOD
120
+ sourceNamespace: $source_namespace"
121
+ if [[ -n "$starting_csv" ]]; then
122
+ yaml+="
123
+ startingCSV: $starting_csv"
124
+ fi
125
+ echo "$yaml" | oc apply -f -
122
126
  return 0
123
127
  }
124
128
 
125
- check_operator_status() {
126
- local timeout=${1:-300} namespace=$2 operator_name=$3 expected_status=${4:-Succeeded}
127
- log::info "Checking operator '${operator_name}' in '${namespace}' (timeout ${timeout}s, expected: ${expected_status})"
129
+ # Wait for an operator CSV to reach a status phase.
130
+ # Uses OLM label selector (operators.coreos.com/<package>.<namespace>) which is
131
+ # deterministic, unlike spec.displayName which varies across channels/versions.
132
+ wait_for_operator() {
133
+ local timeout=${1:-300} namespace=$2 package=$3 expected_status=${4:-Succeeded}
134
+ local label="operators.coreos.com/${package}.${namespace}"
135
+ log::info "Waiting for operator '${package}' in '${namespace}' (label=${label}, timeout ${timeout}s, expected: ${expected_status})"
128
136
  timeout "${timeout}" bash -c "
129
137
  while true; do
130
- CURRENT_PHASE=\$(oc get csv -n '${namespace}' -o jsonpath='{.items[?(@.spec.displayName==\"${operator_name}\")].status.phase}')
131
- echo \"[check_operator_status] Phase: \${CURRENT_PHASE}\" >&2
132
- [[ \"\${CURRENT_PHASE}\" == \"${expected_status}\" ]] && echo \"[check_operator_status] Operator reached ${expected_status}\" >&2 && break
138
+ CURRENT_PHASE=\$(oc get csv -n '${namespace}' -l '${label}' -o jsonpath='{.items[0].status.phase}' 2>/dev/null)
139
+ echo \"[wait_for_operator] Phase: \${CURRENT_PHASE}\" >&2
140
+ [[ \"\${CURRENT_PHASE}\" == \"${expected_status}\" ]] && echo \"[wait_for_operator] Operator reached ${expected_status}\" >&2 && break
133
141
  sleep 10
134
142
  done
135
- " || { log::error "Operator did not reach ${expected_status} in time."; return 1; }
143
+ " || { log::error "Operator '${package}' did not reach ${expected_status} in time."; return 1; }
136
144
  }
137
145
 
138
146
  install_serverless_logic_ocp_operator() {
139
- install_subscription logic-operator openshift-operators stable logic-operator redhat-operators openshift-marketplace
147
+ install_subscription logic-operator openshift-operators stable logic-operator redhat-operators openshift-marketplace logic-operator.v1.37.2
140
148
  return 0
141
149
  }
142
150
  waitfor_serverless_logic_ocp_operator() {
143
- check_operator_status 500 openshift-operators "Red Hat OpenShift Serverless Logic" Succeeded
151
+ wait_for_operator 500 openshift-operators logic-operator Succeeded
144
152
  return 0
145
153
  }
146
154
 
@@ -149,7 +157,7 @@ install_serverless_ocp_operator() {
149
157
  return 0
150
158
  }
151
159
  waitfor_serverless_ocp_operator() {
152
- check_operator_status 300 openshift-operators "Red Hat OpenShift Serverless" Succeeded
160
+ wait_for_operator 300 openshift-operators serverless-operator Succeeded
153
161
  return 0
154
162
  }
155
163
 
@@ -28,9 +28,11 @@ export interface DynamicPluginsConfig {
28
28
  export declare function isNightlyJob(): boolean;
29
29
  /**
30
30
  * Extracts the plugin name from a package path or OCI reference.
31
+ * Strips the `-dynamic` suffix so local paths and OCI refs for the same
32
+ * logical plugin produce the same key.
31
33
  *
32
34
  * Handles various formats:
33
- * - Local path: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar
35
+ * - Local path: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar-dynamic
34
36
  * - OCI with alias: oci://quay.io/rhdh/plugin@sha256:...!backstage-community-plugin-tech-radar
35
37
  * - OCI without alias: oci://quay.io/rhdh/backstage-community-plugin-tech-radar:tag
36
38
  */
@@ -1 +1 @@
1
- {"version":3,"file":"plugin-metadata.d.ts","sourceRoot":"","sources":["../../src/utils/plugin-metadata.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD,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,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;AAID;;;;;;;;;GASG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAqBtC;AAID;;;;;;;GAOG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAI5D;AAYD,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD,wBAAgB,oBAAoB,CAClC,YAAY,GAAE,MAA8B,GAC3C,MAAM,GAAG,IAAI,CAQf;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAyBzB;AAED,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAwBtC;AA2JD;;;;;;;GAOG;AACH;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAMT;AAqGD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAW7E;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,YAAY,GAAE,MAA8B,GAC3C,OAAO,CAAC,oBAAoB,CAAC,CAwB/B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,oBAAoB,EAC5B,YAAY,GAAE,MAA8B,GAC3C,OAAO,CAAC,oBAAoB,CAAC,CA6B/B"}
1
+ {"version":3,"file":"plugin-metadata.d.ts","sourceRoot":"","sources":["../../src/utils/plugin-metadata.ts"],"names":[],"mappings":"AAWA,MAAM,WAAW,cAAc;IAC7B,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACtC,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAC;CACpB;AAaD,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,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;AAID;;;;;;;;;GASG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAqBtC;AAID;;;;;;;;;GASG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAI5D;AAYD,eAAO,MAAM,qBAAqB,gBAAgB,CAAC;AAEnD,wBAAgB,oBAAoB,CAClC,YAAY,GAAE,MAA8B,GAC3C,MAAM,GAAG,IAAI,CAQf;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,cAAc,CAAC,CAyBzB;AAED,wBAAsB,qBAAqB,CACzC,WAAW,EAAE,MAAM,GAClB,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,cAAc,CAAC,CAAC,CAwBtC;AA2JD;;;;;;;GAOG;AACH;;;;;GAKG;AACH,wBAAgB,2BAA2B,CAAC,KAAK,EAAE;IACjD,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,GAAG,MAAM,CAMT;AAqGD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,MAAM,EAAE,GAAG,oBAAoB,CAW7E;AAED;;;;;;;GAOG;AACH,wBAAsB,2BAA2B,CAC/C,YAAY,GAAE,MAA8B,GAC3C,OAAO,CAAC,oBAAoB,CAAC,CAwB/B;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAsB,2BAA2B,CAC/C,MAAM,EAAE,oBAAoB,EAC5B,YAAY,GAAE,MAA8B,GAC3C,OAAO,CAAC,oBAAoB,CAAC,CA6B/B"}
@@ -35,16 +35,18 @@ export function isNightlyJob() {
35
35
  // ── Utilities ─────────────────────────────────────────────────────────────────
36
36
  /**
37
37
  * Extracts the plugin name from a package path or OCI reference.
38
+ * Strips the `-dynamic` suffix so local paths and OCI refs for the same
39
+ * logical plugin produce the same key.
38
40
  *
39
41
  * Handles various formats:
40
- * - Local path: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar
42
+ * - Local path: ./dynamic-plugins/dist/backstage-community-plugin-tech-radar-dynamic
41
43
  * - OCI with alias: oci://quay.io/rhdh/plugin@sha256:...!backstage-community-plugin-tech-radar
42
44
  * - OCI without alias: oci://quay.io/rhdh/backstage-community-plugin-tech-radar:tag
43
45
  */
44
46
  export function extractPluginName(packageRef) {
45
47
  const ref = packageRef.includes("!") ? packageRef.split("!")[0] : packageRef;
46
48
  const match = ref.match(/\/([^/:@]+)(?:[:@].*)?$/);
47
- return match?.[1] || packageRef;
49
+ return (match?.[1] || packageRef).replace(/-dynamic$/, "");
48
50
  }
49
51
  /**
50
52
  * Derives the displayName from a packageName.
@@ -207,7 +209,7 @@ export function getNormalizedPluginMergeKey(entry) {
207
209
  if (pkg === undefined || pkg === "") {
208
210
  return "";
209
211
  }
210
- return extractPluginName(pkg).replace(/-dynamic$/, "");
212
+ return extractPluginName(pkg);
211
213
  }
212
214
  async function resolvePluginPackages(plugins, metadataMap, metadataPath) {
213
215
  // Build PR OCI URLs if applicable
@@ -256,6 +256,61 @@ describe("processPluginsForDeployment — PR mode", () => {
256
256
  await fs.remove(metadataDir);
257
257
  }
258
258
  });
259
+ // ── -dynamic suffix normalization ────────────────────────────────────────
260
+ describe("-dynamic suffix normalization", () => {
261
+ it("resolves OCI plugin to metadata when dynamicArtifact has -dynamic suffix", async () => {
262
+ const metadataDir = await createMetadataFixture([
263
+ {
264
+ name: "backstage-plugin-catalog-backend-module-github",
265
+ packageName: "@backstage/plugin-catalog-backend-module-github",
266
+ dynamicArtifact: "./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic",
267
+ appConfigExamples: {
268
+ catalog: { providers: { github: { org: "test" } } },
269
+ },
270
+ },
271
+ ]);
272
+ try {
273
+ const config = {
274
+ plugins: [
275
+ {
276
+ package: "oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-plugin-catalog-backend-module-github:bs_1.45.3__0.11.2",
277
+ disabled: false,
278
+ },
279
+ ],
280
+ };
281
+ const result = await processPluginsForDeployment(config, metadataDir);
282
+ assert.ok(result.plugins[0].pluginConfig, "metadata config must be injected even when dynamicArtifact has -dynamic suffix but OCI URL does not");
283
+ assert.deepStrictEqual(result.plugins[0].pluginConfig, { catalog: { providers: { github: { org: "test" } } } }, "injected config must match metadata appConfigExamples");
284
+ }
285
+ finally {
286
+ await fs.remove(metadataDir);
287
+ }
288
+ });
289
+ it("keeps local -dynamic path unchanged when metadata also has -dynamic", async () => {
290
+ const metadataDir = await createMetadataFixture([
291
+ {
292
+ name: "backstage-plugin-catalog-backend-module-github",
293
+ packageName: "@backstage/plugin-catalog-backend-module-github",
294
+ dynamicArtifact: "./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic",
295
+ },
296
+ ]);
297
+ try {
298
+ const config = {
299
+ plugins: [
300
+ {
301
+ package: "./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic",
302
+ disabled: false,
303
+ },
304
+ ],
305
+ };
306
+ const result = await processPluginsForDeployment(config, metadataDir);
307
+ assert.strictEqual(result.plugins[0].package, "./dynamic-plugins/dist/backstage-plugin-catalog-backend-module-github-dynamic", "local path with -dynamic must stay unchanged");
308
+ }
309
+ finally {
310
+ await fs.remove(metadataDir);
311
+ }
312
+ });
313
+ });
259
314
  // ── PR vs nightly precedence ────────────────────────────────────────────
260
315
  describe("PR vs nightly precedence", () => {
261
316
  it("isNightlyJob returns false when both GIT_PR_NUMBER and E2E_NIGHTLY_MODE are set", () => {
@@ -18,8 +18,8 @@ describe("extractPluginName", () => {
18
18
  it("extracts name from OCI URL with tag only (no alias)", () => {
19
19
  assert.strictEqual(extractPluginName("oci://ghcr.io/redhat-developer/rhdh-plugin-export-overlays/backstage-community-plugin-tekton:bs_1.45.3__3.33.3"), "backstage-community-plugin-tekton");
20
20
  });
21
- it("extracts name from local path", () => {
22
- assert.strictEqual(extractPluginName("./dynamic-plugins/dist/backstage-community-plugin-keycloak-dynamic"), "backstage-community-plugin-keycloak-dynamic");
21
+ it("extracts name from local path and strips -dynamic suffix", () => {
22
+ assert.strictEqual(extractPluginName("./dynamic-plugins/dist/backstage-community-plugin-keycloak-dynamic"), "backstage-community-plugin-keycloak");
23
23
  });
24
24
  it("extracts name from OCI URL with digest but no alias", () => {
25
25
  assert.strictEqual(extractPluginName("oci://quay.io/rhdh/backstage-plugin-events-backend-module-github@sha256:c1d17d47aaa"), "backstage-plugin-events-backend-module-github");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@red-hat-developer-hub/e2e-test-utils",
3
- "version": "1.1.30",
3
+ "version": "1.1.32",
4
4
  "description": "Test utilities for RHDH E2E tests",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {