Skip to content

test(version-management): add e2e integration tests for plugin check-versions and upgrade - #231

Open
gashcrumb wants to merge 3 commits into
redhat-developer:mainfrom
gashcrumb:test/plugin-version-management-e2e
Open

gashcrumb wants to merge 3 commits into
redhat-developer:mainfrom
gashcrumb:test/plugin-version-management-e2e

Conversation

@gashcrumb

Copy link
Copy Markdown
Member

Summary

Adds an automated end-to-end integration test suite (e2e-tests/plugin-version-management.test.ts) covering rhdh-cli plugin check-versions and rhdh-cli plugin upgrade across real plugin file structures, fulfilling the E2E testing requirements of RHIDP-16669.

Key Coverage

  • Dependency Auditing (plugin check-versions & alias versions:lint):
    • Verifies exit code 1 when dependencies drift or mismatch from target RHDH release.
    • Verifies human-readable remediation hint (Run rhdh-cli plugin upgrade 2.1.0) and structured --json output (valid: false, status: "mismatch").
    • Verifies exit code 0 when dependencies align.
    • Registers the missing versions:lint alias in src/commands/index.ts.
  • Dependency Upgrading (plugin upgrade & alias versions:bump):
    • --dry-run: Verifies table diff output while ensuring package.json and backstage.json remain untouched on disk.
    • --skip-install: Verifies package.json and backstage.json update to target manifest versions without triggering package manager install.
    • Full upgrade: Verifies full upgrade with package manager install (yarn install) updating yarn.lock.
  • Multi-step Release Upgrade Lifecycle:
    • Tests step-by-step upgrade across release baselines (1.8 -> 2.0 -> 2.1) without version corruption or loss of third-party dependencies.
  • Post-Upgrade Dynamic Plugin Export:
    • Confirms yarn tsc, yarn build, and rhdh-cli plugin export run cleanly on the upgraded plugin, generating dist-dynamic/package.json with matching backstage.supported-versions and zero version conflicts.
  • Air-Gapped / Offline Execution:
    • Verifies check-versions and upgrade with --manifest-file <path> and RHDH_OFFLINE=true without external network calls.
  • Test Infrastructure (e2e-tests/support/plugin-export-build.ts):
    • Enriches the thrown Error from runCommand with stdout, stderr, code, and signal properties for robust error assertions.

Follow-up documentation refactoring across all on-ramp workflows (plugin new, plugin dev, plugin check-versions, plugin upgrade) will be delivered in a subsequent PR.

…versions and upgrade

- Add e2e-tests/plugin-version-management.test.ts verifying plugin check-versions and upgrade lifecycle
- Test version mismatch detection, remediation output, and --json structured output
- Test non-destructive --dry-run and --skip-install upgrade modes
- Test full upgrade with package manager install and lockfile synchronization
- Test multi-step version upgrade lifecycle across releases (1.8 -> 2.0 -> 2.1)
- Test dynamic plugin export of an upgraded plugin fixture
- Test offline and air-gapped auditing and upgrading via --manifest-file and RHDH_OFFLINE=true
- Register versions:lint alias for check-versions in src/commands/index.ts
- Enrich runCommand Error with stdout, stderr, code, and signal properties

Assisted-By: opencode
Signed-off-by: Stan Lewis <gashcrumb@gmail.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
…xport-build

- Move runExpectingFailure into e2e-tests/support/plugin-export-build.ts
- Share runExpectingFailure across plugin-dev.test.ts and plugin-version-management.test.ts
- Resolve SonarCloud code duplication quality gate failure

Assisted-By: opencode
Signed-off-by: Stan Lewis <gashcrumb@gmail.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
@gashcrumb

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

🤖 Review · ⚠️ Cancelled · Started 6:24 PM UTC · Ended 6:35 PM UTC

Commit: 9ce0e86 · View workflow run →

- Disable immutable installs (YARN_ENABLE_IMMUTABLE_INSTALLS=false) during upgrade's yarn install step
- Allow Yarn Berry to update yarn.lock when running under CI=true or PR workflows
- Pass YARN_ENABLE_IMMUTABLE_INSTALLS=false in e2e version management upgrade test

Assisted-By: opencode
Signed-off-by: Stan Lewis <gashcrumb@gmail.com>

rh-pre-commit.version: 2.4.0
rh-pre-commit.check-secrets: ENABLED
@sonarqubecloud

sonarqubecloud Bot commented Oct 2, 2026

Copy link
Copy Markdown

@gashcrumb

Copy link
Copy Markdown
Member Author

/fs-review

@fullsend-ai-review

fullsend-ai-review Bot commented Oct 2, 2026 •

Copy link
Copy Markdown

🤖 Finished Review · ✅ Success · Started 6:46 PM UTC · Completed 7:11 PM UTC

Commit: c442487 · View workflow run →

Runtime: claude · Model: sonnet → claude-sonnet-4-6 · Effort: high · Cost: $4.32

@fullsend-ai-review fullsend-ai-review Bot added the risk/moderate PR risk: moderate label Oct 2, 2026
@fullsend-ai-review

Copy link
Copy Markdown

Risk Assessment: moderate (2/5)

Details

Primarily a test-addition PR with two small production changes; large blast-radius classification is the dominant risk signal but is offset by high test file ratio, no protected or security-sensitive paths, and a well-scoped, easily reversible change set.

@fullsend-ai-review

Copy link
Copy Markdown

Review

Findings

Medium

  • [pattern-violation] e2e-tests/plugin-dev.test.ts:22 — RunCommandOptions is still imported after its only consumer (the local runExpectingFailure function) was removed and promoted to the shared support module. This stale import will produce an unused-variable lint error and fail yarn lint:check in CI.
    Remediation: Remove RunCommandOptions from the import block.

  • [incomplete-doc] README.md:43 — The "Checking Plugin Versions" section documents plugin check-versions but omits the versions:lint alias introduced by this PR. The symmetrical "Upgrading Plugin Versions" section explicitly documents the versions:bump alias at line 65. This creates an asymmetric documentation gap for users discovering the CLI.
    Remediation: Add a sentence analogous to line 65: "Its plugin versions:lint alias provides the same behavior."

Low

  • [test-correctness] e2e-tests/plugin-version-management.test.ts:345 — The multi-step test asserts upgrade20Json.backstageVersion === '1.52.0' and pkgAfter20.dependencies['@backstage/core-plugin-api'] === '^1.12.7' without pinning to offline mode. Tier-1 remote fetch from the RHDH release-2.0 branch takes precedence when online. RHDH 2.0 is a frozen GA release so practical flakiness risk is low — but the unnecessary network dependency could produce false-negatives if the remote is transiently unavailable.
    Remediation: Add RHDH_OFFLINE: 'true' to the env for the multi-step upgrade/check calls, or use --manifest-file with a local fixture manifest (as the air-gapped describe block does) to make assertions fully deterministic.

  • [test-correctness] e2e-tests/plugin-version-management.test.ts:204 — The "dependency upgrading" beforeEach only re-skews two specific packages without a matching afterEach to restore the directory. After the --skip-install test fully upgrades all packages, subsequent beforeEach calls produce a mixed state. Test 3 partially compensates by manually re-applying skewedPackageJson, but the design is fragile against future test additions.
    Remediation: Add an afterEach that restores pluginDir/package.json and backstage.json from a snapshot taken in beforeAll, mirroring the pattern used in the "dependency auditing" block.

  • [test-correctness] e2e-tests/plugin-version-management.test.ts:469 — The offlineDir fixture in beforeAll does not include a backstage.json file. syncBackstageJson silently skips when the file is absent, so the backstage.json sync path is not exercised in offline mode. No assertion fails, but the gap is silent.
    Remediation: Add a backstage.json (e.g. { version: '1.54.6' }) to the offline fixture and assert parsedUpgrade.updatedFiles includes 'backstage.json' after upgrade.

  • [scope-creep] src/commands/upgrade/command.ts:215 — The PR is typed test(version-management) via Conventional Commits (enforced by pr-semantic.yaml), but includes two production code changes: the versions:lint alias registration and the YARN_ENABLE_IMMUTABLE_INSTALLS env-var management. The PR body is transparent about both changes.
    Remediation: Amend the PR title to fix(version-management) to reflect the production fixes included, or split the production changes into a preceding fix commit.

  • [incomplete-doc] README.md:67 — The "Upgrading Plugin Versions" section notes --skip-install to avoid lockfile mutation, but does not mention that the CLI now automatically sets YARN_ENABLE_IMMUTABLE_INSTALLS=false when the install step runs (new behavior in this PR). Users in CI with strict immutable-lockfile policies may be surprised when the lockfile is updated.
    Remediation: Add a note explaining that the CLI temporarily disables YARN_ENABLE_IMMUTABLE_INSTALLS during the install step, and recommend --skip-install for environments that need strict lockfile enforcement.

  • [code-organization] src/commands/upgrade/command.ts:220 — runInstallDependencies temporarily mutates process.env.YARN_ENABLE_IMMUTABLE_INSTALLS globally rather than passing the override via subprocess spawn options. The save/restore logic in finally is correct (handles unset, set, and non-yarn cases), but global env mutation is unnecessary for a subprocess invocation.
    Remediation: Pass the override via Task.forCommand's spawn env option (env: { ...process.env, YARN_ENABLE_IMMUTABLE_INSTALLS: 'false' }) to avoid mutating the global environment.


Next steps:

  • /fs-fix — agent addresses review findings automatically
  • /fs-fix <your instruction> — agent fixes with your specific guidance
  • Push commits directly — review re-runs automatically on push
  • /fs-fix-stop — disable automatic fix runs for this PR

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note: The following review comments could not be posted on the diff (GitHub returned 422) and are included here instead:

  • e2e-tests/plugin-version-management.test.ts (file-level): Line 469 · [low] test-correctness

The offlineDir fixture in beforeAll does not include a backstage.json file. syncBackstageJson silently skips when the file is absent, leaving the backstage.json sync path untested in offline mode. No assertion fails, but the gap is silent.

Suggested fix: Add a backstage.json to the offline fixture and assert parsedUpgrade.updatedFiles includes backstage.json after upgrade.

@fullsend-ai-review fullsend-ai-review Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

See the review comment for full details.

runCommand,
runExpectingFailure,
RunCommandOptions,
} from './support/plugin-export-build';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[medium] pattern-violation

RunCommandOptions is imported but no longer used anywhere in the file. The only consumer was the local runExpectingFailure function, which was removed and promoted to the shared support module in this PR. The stale import will produce an unused-import lint error and fail yarn lint:check in CI.

Suggested fix: Remove RunCommandOptions from the import block on line 22.

// Ensure pluginDir is aligned with 2.1.0
await runCommand(`"${rhdhCli}" plugin upgrade 2.1.0 --skip-install`, {
cwd: pluginDir,
});

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] test-correctness

The multi-step test asserts upgrade20Json.backstageVersion equals 1.52.0 and pkgAfter20.dependencies for @backstage/core-plugin-api equals ^1.12.7 without pinning to offline mode. Tier-1 remote fetch from the RHDH release-2.0 branch takes precedence when online. RHDH 2.0 is a frozen GA release so practical flakiness risk is low, but the unnecessary network dependency could produce false-negatives if the remote is transiently unavailable.

Suggested fix: Add RHDH_OFFLINE: true to the env for the multi-step upgrade and check calls, or use --manifest-file with a local fixture manifest to make the assertions fully deterministic.

const currentPkg = await fs.readJson(
path.join(pluginDir, 'package.json'),
);
expect(currentPkg.dependencies['@backstage/core-plugin-api']).not.toBe(

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] test-correctness

The dependency upgrading describe block has a beforeEach that only re-skews two specific packages without a matching afterEach to restore the directory. After the --skip-install test fully upgrades all packages, subsequent beforeEach calls produce a mixed state. Test 3 partially compensates by manually re-applying skewedPackageJson, but the design is fragile against future test additions.

Suggested fix: Add an afterEach that restores pluginDir/package.json and backstage.json from a snapshot taken in beforeAll, mirroring the pattern used in the dependency auditing block.

*/
async function runInstallDependencies(targetDir: string): Promise<boolean> {
const pm = await detectPackageManager(targetDir);
const prevImmutable = process.env.YARN_ENABLE_IMMUTABLE_INSTALLS;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] scope-creep

The PR is typed test(version-management) via Conventional Commits enforced by pr-semantic.yaml, but includes two production code changes: the versions:lint alias registration and the YARN_ENABLE_IMMUTABLE_INSTALLS env-var management. The PR body is transparent about both.

Suggested fix: Amend the PR title to fix(version-management) to reflect the production fixes included, or split them into a preceding fix commit.

// Upgrading dependencies inherently mutates the lockfile. Ensure Yarn Berry
// does not block lockfile updates when running in CI or automated PR workflows.
if (pm === 'yarn') {
process.env.YARN_ENABLE_IMMUTABLE_INSTALLS = 'false';

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[low] code-organization

runInstallDependencies temporarily mutates process.env.YARN_ENABLE_IMMUTABLE_INSTALLS globally rather than passing the override via subprocess spawn options. The save/restore logic in finally is correct (handles unset, set, and non-yarn cases), but global env mutation is unnecessary for a subprocess invocation.

Suggested fix: Pass the override via Task.forCommand spawn env option using env: { ...process.env, YARN_ENABLE_IMMUTABLE_INSTALLS: false } to avoid mutating the global environment.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

risk/moderate PR risk: moderate

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant