Skip to content

Commit bf80044

Browse files
committed
feat(workflows): introduce computed image tag prefix for metadata validation
This update adds a new input, `computed-image-tag-prefix`, to workflows for better handling of image tag prefixes based on backstage compatibility. The validation logic is adjusted to utilize this computed prefix, ensuring accurate OCI tag checks for both compatible and incompatible workspaces. Assisted-by: Cursor Signed-off-by: David Festal <dfestal@redhat.com>
1 parent 67b355d commit bf80044

5 files changed

Lines changed: 106 additions & 16 deletions

File tree

.github/workflows/export-dynamic.yaml

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,7 +91,15 @@ on:
9191
description: Optional prefix to prepend to the plugin version in the image tag
9292
type: string
9393
required: false
94-
94+
95+
computed-image-tag-prefix:
96+
description: >
97+
The computed image tag prefix reflecting backstage compatibility
98+
(e.g., "bs_1.48.3__" for compatible, "next__" for incompatible).
99+
Used by metadata validation to decide whether OCI tag checks apply.
100+
type: string
101+
required: false
102+
95103
publish-release-assets:
96104
description:
97105
Whether the dynamic plugin archives should be published as GitHub release assets or pushed as workflow
@@ -413,4 +421,4 @@ jobs:
413421
plugins-root: ${{ github.workspace }}/source-repo/${{inputs.plugins-root}}
414422
target-backstage-version: ${{ inputs.target-backstage-version }}
415423
image-repository-prefix: ${{ steps.set-image-tag-name.outputs.IMAGE_REPOSITORY_PREFIX }}
416-
image-tag-prefix: ${{ inputs.image-tag-prefix }}
424+
computed-image-tag-prefix: ${{ inputs.computed-image-tag-prefix }}

.github/workflows/export-workspaces-as-dynamic.yaml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,7 @@ jobs:
271271
publish-container: ${{ inputs.publish-container }}
272272
image-repository-prefix: ${{ inputs.image-repository-prefix }}
273273
image-tag-prefix: ${{ inputs.image-tag-prefix != '' && inputs.image-tag-prefix || matrix.workspace.computed-image-tag-prefix }}
274+
computed-image-tag-prefix: ${{ matrix.workspace.computed-image-tag-prefix }}
274275
target-backstage-version: ${{ needs.prepare.outputs.backstage-version }}
275276
last-publish-commit: ${{ inputs.last-publish-commit }}
276277
image-registry-user: ${{ inputs.image-registry-user }}

.github/workflows/test-validate-metadata.yaml

Lines changed: 82 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -399,8 +399,8 @@ jobs:
399399
message: 'plugins-list.yaml must be a YAML dictionary with plugin paths as keys'
400400
});
401401
402-
test-validation-next-prefix-skips-tag:
403-
name: Test Validation (next__ prefix skips OCI tag check)
402+
test-validation-incompatible-workspace-skips-tag:
403+
name: Test Validation (incompatible workspace skips OCI tag check)
404404
runs-on: ubuntu-latest
405405
steps:
406406
- name: Checkout repository
@@ -411,15 +411,15 @@ jobs:
411411
with:
412412
node-version: 24.x
413413

414-
- name: Run Validate Metadata with next__ prefix
414+
- name: Run Validate Metadata with next__ computed prefix
415415
id: validate
416416
uses: ./validate-metadata
417417
with:
418418
overlay-root: ${{ env.TEST_DIR }}/cases/next-prefix-skip
419419
plugins-root: ${{ env.TEST_DIR }}/source
420420
target-backstage-version: ${{ env.TARGET_BACKSTAGE_VERSION }}
421421
image-repository-prefix: ${{ env.IMAGE_REPOSITORY_PREFIX }}
422-
image-tag-prefix: next__
422+
computed-image-tag-prefix: next__
423423

424424
- name: Verify validation passed despite stale OCI tag
425425
env:
@@ -432,7 +432,84 @@ jobs:
432432
const { VALIDATION_PASSED, VALIDATION_ERROR_COUNT, VALIDATION_ERRORS } = process.env;
433433
434434
// Metadata has bs_1.40.0__1.0.0 which doesn't match target 1.42.5,
435-
// but with next__ prefix the OCI tag check is skipped
435+
// but with next__ computed prefix the OCI tag check is skipped
436+
assert.equal(VALIDATION_PASSED, 'true');
437+
assert.equal(VALIDATION_ERROR_COUNT, '0');
438+
assert.equal(VALIDATION_ERRORS, '[]');
439+
440+
test-validation-pr-compatible-validates-tag:
441+
name: Test Validation (PR build with compatible workspace validates OCI tag)
442+
runs-on: ubuntu-latest
443+
steps:
444+
- name: Checkout repository
445+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
446+
447+
- name: Setup Node.js 24.x
448+
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
449+
with:
450+
node-version: 24.x
451+
452+
- name: Run Validate Metadata with bs_ computed prefix (simulating compatible PR)
453+
id: validate
454+
uses: ./validate-metadata
455+
with:
456+
overlay-root: ${{ env.TEST_DIR }}/cases/pass
457+
plugins-root: ${{ env.TEST_DIR }}/source
458+
target-backstage-version: ${{ env.TARGET_BACKSTAGE_VERSION }}
459+
image-repository-prefix: ${{ env.IMAGE_REPOSITORY_PREFIX }}
460+
computed-image-tag-prefix: bs_${{ env.TARGET_BACKSTAGE_VERSION }}__
461+
462+
- name: Verify validation passed (metadata tag matches computed prefix)
463+
env:
464+
VALIDATION_PASSED: ${{ steps.validate.outputs.validation-passed }}
465+
VALIDATION_ERROR_COUNT: ${{ steps.validate.outputs.validation-error-count }}
466+
VALIDATION_ERRORS: ${{ steps.validate.outputs.validation-errors }}
467+
shell: node {0}
468+
run: |
469+
import assert from 'node:assert/strict';
470+
const { VALIDATION_PASSED, VALIDATION_ERROR_COUNT, VALIDATION_ERRORS } = process.env;
471+
472+
// Even though a real PR build would use pr_N__ as the image-tag-prefix,
473+
// the computed-image-tag-prefix is bs_<target>__ for compatible workspaces,
474+
// so OCI tag validation runs and passes against the production tag.
475+
assert.equal(VALIDATION_PASSED, 'true');
476+
assert.equal(VALIDATION_ERROR_COUNT, '0');
477+
assert.equal(VALIDATION_ERRORS, '[]');
478+
479+
test-validation-pr-incompatible-skips-tag:
480+
name: Test Validation (PR build with incompatible workspace skips OCI tag check)
481+
runs-on: ubuntu-latest
482+
steps:
483+
- name: Checkout repository
484+
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
485+
486+
- name: Setup Node.js 24.x
487+
uses: actions/setup-node@53b83947a5a98c8d113130e565377fae1a50d02f # v6.3.0
488+
with:
489+
node-version: 24.x
490+
491+
- name: Run Validate Metadata with next__ computed prefix (simulating incompatible PR)
492+
id: validate
493+
uses: ./validate-metadata
494+
with:
495+
overlay-root: ${{ env.TEST_DIR }}/cases/next-prefix-skip
496+
plugins-root: ${{ env.TEST_DIR }}/source
497+
target-backstage-version: ${{ env.TARGET_BACKSTAGE_VERSION }}
498+
image-repository-prefix: ${{ env.IMAGE_REPOSITORY_PREFIX }}
499+
computed-image-tag-prefix: next__
500+
501+
- name: Verify validation passed despite stale OCI tag
502+
env:
503+
VALIDATION_PASSED: ${{ steps.validate.outputs.validation-passed }}
504+
VALIDATION_ERROR_COUNT: ${{ steps.validate.outputs.validation-error-count }}
505+
VALIDATION_ERRORS: ${{ steps.validate.outputs.validation-errors }}
506+
shell: node {0}
507+
run: |
508+
import assert from 'node:assert/strict';
509+
const { VALIDATION_PASSED, VALIDATION_ERROR_COUNT, VALIDATION_ERRORS } = process.env;
510+
511+
// PR build of an incompatible workspace: computed prefix is next__,
512+
// so OCI tag validation is skipped even though metadata has stale bs_1.40.0__
436513
assert.equal(VALIDATION_PASSED, 'true');
437514
assert.equal(VALIDATION_ERROR_COUNT, '0');
438515
assert.equal(VALIDATION_ERRORS, '[]');

validate-metadata/action.yaml

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -14,8 +14,11 @@ inputs:
1414
description: Repository prefix for validating OCI reference format in dynamicArtifact
1515
required: false
1616
default: ""
17-
image-tag-prefix:
18-
description: OCI image tag prefix used by the export (e.g., "bs_1.48.3__", "next__", "pr_42__"). When "next__", OCI tag validation is skipped since the workspace is backstage-incompatible.
17+
computed-image-tag-prefix:
18+
description: >
19+
The computed image tag prefix reflecting backstage compatibility
20+
(e.g., "bs_1.48.3__" for compatible, "next__" for incompatible).
21+
When "next__", OCI tag validation is skipped since the workspace is backstage-incompatible.
1922
required: false
2023
default: ""
2124

@@ -42,7 +45,7 @@ runs:
4245
INPUTS_PLUGINS_ROOT: ${{ inputs.plugins-root }}
4346
INPUTS_TARGET_BACKSTAGE_VERSION: ${{ inputs.target-backstage-version }}
4447
INPUTS_IMAGE_REPOSITORY_PREFIX: ${{ inputs.image-repository-prefix }}
45-
INPUTS_IMAGE_TAG_PREFIX: ${{ inputs.image-tag-prefix }}
48+
INPUTS_COMPUTED_IMAGE_TAG_PREFIX: ${{ inputs.computed-image-tag-prefix }}
4649
run: |
4750
npm install
4851
node validate-metadata.ts

validate-metadata/validate-metadata.ts

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ const OVERLAY_ROOT = process.env.INPUTS_OVERLAY_ROOT;
7878
const PLUGINS_ROOT = process.env.INPUTS_PLUGINS_ROOT;
7979
const TARGET_BACKSTAGE_VERSION = process.env.INPUTS_TARGET_BACKSTAGE_VERSION;
8080
const IMAGE_REPOSITORY_PREFIX = process.env.INPUTS_IMAGE_REPOSITORY_PREFIX || '';
81-
const IMAGE_TAG_PREFIX = process.env.INPUTS_IMAGE_TAG_PREFIX || '';
81+
const COMPUTED_IMAGE_TAG_PREFIX = process.env.INPUTS_COMPUTED_IMAGE_TAG_PREFIX || '';
8282

8383
// Validate required environment variables
8484
if (!OVERLAY_ROOT) {
@@ -362,12 +362,13 @@ function validateOciReference(
362362
): void {
363363
const { reference, tag } = parseOciReference(dynamicArtifact);
364364

365-
// When the export uses next__ (workspace is backstage-incompatible),
366-
// skip the tag prefix check -- the metadata tag is a remnant from the
365+
// Skip the tag prefix check when the workspace is backstage-incompatible
366+
// (computed prefix is "next__"). The metadata tag is a remnant from the
367367
// last compatible state and will self-correct on the next compatible update.
368-
if (IMAGE_TAG_PREFIX !== 'next__') {
369-
const expectedTag = IMAGE_TAG_PREFIX
370-
? `${IMAGE_TAG_PREFIX}${pluginVersion}`
368+
// This applies regardless of the build prefix (release or PR).
369+
if (COMPUTED_IMAGE_TAG_PREFIX !== 'next__') {
370+
const expectedTag = COMPUTED_IMAGE_TAG_PREFIX
371+
? `${COMPUTED_IMAGE_TAG_PREFIX}${pluginVersion}`
371372
: `bs_${TARGET_BACKSTAGE_VERSION}__${pluginVersion}`;
372373

373374
if (tag !== expectedTag) {

0 commit comments

Comments
 (0)