Add detail in error messages when yarn plugin can't detect backstage version

I was confused for ~15 minutes today when updating to using the yarn
plugin. It was failing in docker but not locally, and I didn't know why.
It turned out to be because I forgot to copy the backstage.json into the
docker image. This was confusing, because the error seemed to indicate I
was failing the semver checks. This change propagates error detail down
the line, so people will see the actual cause. (i.e. missing file, no
version field, semver wrong)

Signed-off-by: Riley Martine <rmartine@integralads.com>
This commit is contained in:
Riley Martine
2025-08-26 17:16:38 -06:00
parent bc7d142350
commit 6474b04936
4 changed files with 19 additions and 13 deletions
+1
View File
@@ -31,6 +31,7 @@
},
"dependencies": {
"@backstage/cli-common": "workspace:^",
"@backstage/errors": "workspace:^",
"@backstage/release-manifests": "workspace:^",
"@yarnpkg/core": "^4.4.1",
"@yarnpkg/fslib": "^3.1.2",
@@ -73,17 +73,15 @@ describe('getCurrentBackstageVersion', () => {
});
it.each`
description | content
${'is missing'} | ${{}}
${'is invalid'} | ${{ 'backstage.json': '}{' }}
${'has missing version'} | ${{ 'backstage.json': '{"a":"b"}' }}
${'has invalid version'} | ${{ 'backstage.json': '{"version":"foobar"}' }}
`('throws if backstage.json $description', ({ content }) => {
description | content | message
${'is missing'} | ${{}} | ${/valid version string not found.*no such file/i}
${'is invalid'} | ${{ 'backstage.json': '}{' }} | ${/valid version string not found.*not valid json/i}
${'has missing version'} | ${{ 'backstage.json': '{"a":"b"}' }} | ${/valid version string not found.*version field is missing/i}
${'has invalid version'} | ${{ 'backstage.json': '{"version":"foobar"}' }} | ${/valid version string not found.*exists but is not valid semver/i}
`('throws if backstage.json $description', ({ content, message }) => {
mockDir.addContent(content);
expect(() => getCurrentBackstageVersion()).toThrow(
/valid version string not found/i,
);
expect(() => getCurrentBackstageVersion()).toThrow(message);
});
it('caches repeated calls', () => {
@@ -18,6 +18,7 @@ import assert from 'assert';
import { valid as semverValid } from 'semver';
import { ppath, xfs } from '@yarnpkg/fslib';
import { BACKSTAGE_JSON } from '@backstage/cli-common';
import { ForwardedError } from '@backstage/errors';
import { memoize } from './memoize';
import { getWorkspaceRoot } from './getWorkspaceRoot';
@@ -26,11 +27,16 @@ export const getCurrentBackstageVersion = memoize(() => {
let backstageVersion: string | null = null;
try {
backstageVersion = semverValid(xfs.readJsonSync(backstageJsonPath).version);
const backstageVersionRaw = xfs.readJsonSync(backstageJsonPath).version;
assert(backstageVersionRaw !== undefined, 'Version field is missing');
backstageVersion = semverValid(backstageVersionRaw);
assert(backstageVersion !== null);
} catch {
throw new Error('Valid version string not found in backstage.json');
assert(backstageVersion !== null, 'Version exists but is not valid semver');
} catch (err) {
throw new ForwardedError(
'Valid version string not found in backstage.json',
err,
);
}
return backstageVersion;