Skip to content

Commit 5bc0fec

Browse files
authored
Merge pull request #898 from forcedotcom/wr/fixLatestDependencyBranchScoping
fix: stop scoping LATEST dependency resolution to --branch flag @W-21617695@
2 parents 4131d41 + 081e13f commit 5bc0fec

2 files changed

Lines changed: 79 additions & 4 deletions

File tree

src/package/packageVersionCreate.ts

Lines changed: 28 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -125,22 +125,46 @@ export class PackageVersionCreate {
125125
const branchString = !branch ? 'null' : `'${branch}'`;
126126

127127
// resolve a build number keyword to an actual number, if needed
128-
const resolvedBuildNumber = await this.resolveBuildNumber(versionNumber, dependency.packageId, branch);
128+
let resolvedBuildNumber: string;
129+
let effectiveBranchString = branchString;
130+
try {
131+
resolvedBuildNumber = await this.resolveBuildNumber(versionNumber, dependency.packageId, branch);
132+
} catch (e) {
133+
// when --branch was inherited (not set on the dependency itself) and LATEST resolution fails
134+
// specifically because no version exists on that branch, fall back to null branch
135+
if (
136+
e instanceof Error &&
137+
e.name === 'NoReleaseVersionFoundForBranchError' &&
138+
dependency.branch === undefined &&
139+
this.options.branch &&
140+
buildNumber === BuildNumberToken.LATEST_BUILD_NUMBER_TOKEN
141+
) {
142+
this.logger.info(
143+
`Dependency ${dependency.package ?? dependency.packageId} has no versions on branch '${String(
144+
branch
145+
)}'. Falling back to unscoped (no branch) resolution.`
146+
);
147+
effectiveBranchString = 'null';
148+
resolvedBuildNumber = await this.resolveBuildNumber(versionNumber, dependency.packageId, undefined);
149+
} else {
150+
throw e;
151+
}
152+
}
129153

130154
// now that we have a full build number, query for the associated 04t.
131155
// because the build number may not be unique across versions, add in conditionals for
132156
// the branch or the RELEASED token (if used)
133157
const branchOrReleasedCondition =
134158
buildNumber === BuildNumberToken.RELEASED_BUILD_NUMBER_TOKEN
135159
? 'AND IsReleased = true'
136-
: `AND Branch = ${branchString}`;
160+
: `AND Branch = ${effectiveBranchString}`;
137161
const query = `SELECT SubscriberPackageVersionId FROM Package2Version WHERE Package2Id = '${dependency.packageId}' AND MajorVersion = ${versionNumber.major} AND MinorVersion = ${versionNumber.minor} AND PatchVersion = ${versionNumber.patch} AND BuildNumber = ${resolvedBuildNumber} ${branchOrReleasedCondition}`;
138162
const pkgVerQueryResult = await this.connection.tooling.query<PackagingSObjects.Package2Version>(query);
139163
const subRecords = pkgVerQueryResult.records;
140164
if (!subRecords || subRecords.length !== 1) {
141165
throw messages.createError('versionNumberNotFoundInDevHub', [
142166
dependency.packageId,
143-
branchString,
167+
effectiveBranchString,
144168
versionNumber.toString(),
145169
resolvedBuildNumber,
146170
]);
@@ -155,7 +179,7 @@ export class PackageVersionCreate {
155179
messages.getMessage('buildNumberResolvedForLatest', [
156180
dependency.package,
157181
versionNumber.toString(),
158-
branchString,
182+
effectiveBranchString,
159183
dependency.subscriberPackageVersionId,
160184
])
161185
);

test/package/packageVersionCreate.test.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,57 @@ describe('Package Version Create', () => {
395395
expect(result).to.have.all.keys(expectedKeys);
396396
});
397397

398+
it('should fall back to null branch when --branch is set but dependency has no versions on that branch (LATEST)', async () => {
399+
packageTypeQuery.restore();
400+
401+
const config = project.getSfProjectJson().getContents();
402+
if (isDirWithDependencies(config.packageDirectories[1])) {
403+
config.packageDirectories[1].dependencies[0].package = 'DEP';
404+
config.packageDirectories[1].dependencies[0].versionNumber = '0.1.0.LATEST';
405+
}
406+
project.getSfProjectJson().set('packageDirectories', config.packageDirectories);
407+
await project.getSfProjectJson().write();
408+
409+
// route tooling queries based on query content
410+
// @ts-ignore - returning simplified promise instead of full Query type
411+
packageTypeQuery = $$.SANDBOX.stub(connection.tooling, 'query').callsFake((query: string) => {
412+
if (query.includes('ContainerOptions FROM Package2')) {
413+
return Promise.resolve({ records: [{ ContainerOptions: 'Unlocked' }] });
414+
}
415+
if (query.includes('SELECT Id FROM Package2 WHERE')) {
416+
return Promise.resolve({ records: [{ Id: '0Ho4J000000TNmPXXX' }] });
417+
}
418+
if (query.includes('MAX(BuildNumber)') && query.includes("Branch = 'feature-x'")) {
419+
// no versions on the branch -> triggers fallback
420+
return Promise.resolve({ records: [{ expr0: null }] });
421+
}
422+
if (query.includes('MAX(BuildNumber)') && query.includes('Branch = null')) {
423+
// fallback: resolve from null branch
424+
return Promise.resolve({ records: [{ expr0: 5 }] });
425+
}
426+
if (query.includes('SubscriberPackageVersionId')) {
427+
return Promise.resolve({ records: [{ SubscriberPackageVersionId: '04t000000000001AAA' }] });
428+
}
429+
// default for any other query (e.g., ancestor)
430+
return Promise.resolve({ records: [{ Id: '05i3i000000Gmj6XXX' }] });
431+
});
432+
433+
const pvc = new PackageVersionCreate({
434+
connection,
435+
project,
436+
branch: 'feature-x',
437+
packageId,
438+
skipancestorcheck: true,
439+
});
440+
stubConvert();
441+
442+
const result = await pvc.createPackageVersion();
443+
444+
// the package version create request should use 'feature-x' for the target package
445+
expect(packageCreateStub.firstCall.args[1].Branch).to.equal('feature-x');
446+
expect(result).to.have.all.keys(expectedKeys);
447+
});
448+
398449
it('should create the package version create request with language and API version >= 57.0', async () => {
399450
$$.SANDBOX.stub(connection, 'getApiVersion').returns('57.0');
400451
const pvc = new PackageVersionCreate({ connection, project, language: 'en_US', packageId });

0 commit comments

Comments
 (0)