|
15 | 15 | */ |
16 | 16 | import type { Schema } from '@jsforce/jsforce-node'; |
17 | 17 | import { Connection, Messages, SfError, SfProject } from '@salesforce/core'; |
| 18 | +import { DirectedGraph } from 'graphology'; |
18 | 19 | import { |
19 | 20 | ConvertPackageOptions, |
20 | 21 | PackageCreateOptions, |
@@ -48,6 +49,9 @@ const packagePrefixes = { |
48 | 49 | Messages.importMessagesDirectory(__dirname); |
49 | 50 | const messages = Messages.loadMessages('@salesforce/packaging', 'package'); |
50 | 51 |
|
| 52 | +const packageVersionQuery = 'SELECT SubscriberPackageVersionId, AncestorId, RecommendedVersionId FROM Package2Version'; |
| 53 | +const package2Query = 'SELECT RecommendedVersionId FROM Package2'; |
| 54 | + |
51 | 55 | export const Package2Fields = [ |
52 | 56 | 'Id', |
53 | 57 | 'IsDeleted', |
@@ -325,6 +329,14 @@ export class Package { |
325 | 329 | throw messages.createError('recommendedVersionIdApiPriorTo66Error'); |
326 | 330 | } |
327 | 331 |
|
| 332 | + if (opts.SkipAncestorCheck !== undefined && opts.RecommendedVersionId === undefined) { |
| 333 | + throw messages.createError('skipAncestorCheckRequiresRecommendedVersionIdError'); |
| 334 | + } |
| 335 | + |
| 336 | + if (opts.SkipAncestorCheck === undefined && opts.RecommendedVersionId !== undefined) { |
| 337 | + await this.checkRecommendedVersionAncestors(opts); |
| 338 | + } |
| 339 | + |
328 | 340 | const result = await this.options.connection.tooling.update('Package2', opts); |
329 | 341 | if (!result.success) { |
330 | 342 | throw new SfError(result.errors.join(', ')); |
@@ -354,4 +366,67 @@ export class Package { |
354 | 366 | } |
355 | 367 | return this.packageData; |
356 | 368 | } |
| 369 | + |
| 370 | + /** |
| 371 | + * |
| 372 | + * @param options |
| 373 | + */ |
| 374 | + private async checkRecommendedVersionAncestors(opts: PackageUpdateOptions): Promise<void> { |
| 375 | + if (opts.RecommendedVersionId === undefined) { |
| 376 | + return; |
| 377 | + } |
| 378 | + |
| 379 | + const queryP2 = `${package2Query} WHERE Id = '${this.packageId}'`; |
| 380 | + const priorRecommendedVersionId = (await this.options.connection.tooling.query<PackagingSObjects.Package2>(queryP2)) |
| 381 | + .records[0].RecommendedVersionId; |
| 382 | + |
| 383 | + if (priorRecommendedVersionId === undefined || opts.RecommendedVersionId === priorRecommendedVersionId) { |
| 384 | + return; |
| 385 | + } |
| 386 | + |
| 387 | + const queryP2V = `${packageVersionQuery} WHERE Package2Id = '${this.packageId}'`; |
| 388 | + const result = await this.options.connection.tooling.query<PackageVersionListResult>(queryP2V); |
| 389 | + |
| 390 | + if (result.totalSize === 0) { |
| 391 | + throw messages.createError('noPackageVersionsForGivenPackage2FoundError'); |
| 392 | + } else if (result.totalSize === 1) { |
| 393 | + return; |
| 394 | + } |
| 395 | + |
| 396 | + const graph = new DirectedGraph(); |
| 397 | + const stack: string[] = [opts.RecommendedVersionId]; |
| 398 | + const visited: Set<string> = new Set([opts.RecommendedVersionId]); |
| 399 | + |
| 400 | + result.records.forEach((record) => { |
| 401 | + graph.addNode(record.SubscriberPackageVersionId); |
| 402 | + |
| 403 | + if (record.AncestorId) { |
| 404 | + graph.addNode(record.AncestorId); |
| 405 | + graph.addEdge(record.SubscriberPackageVersionId, record.AncestorId); |
| 406 | + } |
| 407 | + }); |
| 408 | + |
| 409 | + if ( |
| 410 | + graph.outDegree(opts.RecommendedVersionId) > 0 && |
| 411 | + result.records.some((record) => record.SubscriberPackageVersionId === priorRecommendedVersionId) |
| 412 | + ) { |
| 413 | + while (stack.length > 0) { |
| 414 | + const node = stack.pop()!; |
| 415 | + |
| 416 | + for (const neighbor of graph.neighbors(node)) { |
| 417 | + if (neighbor === priorRecommendedVersionId) { |
| 418 | + return; |
| 419 | + } |
| 420 | + |
| 421 | + if (!visited.has(neighbor)) { |
| 422 | + visited.add(neighbor); |
| 423 | + stack.push(neighbor); |
| 424 | + } |
| 425 | + } |
| 426 | + } |
| 427 | + throw messages.createError('recommendedVersionNotAncestorOfPriorVersionError'); |
| 428 | + } else if (graph.outDegree(opts.RecommendedVersionId) === 0) { |
| 429 | + return; |
| 430 | + } |
| 431 | + } |
357 | 432 | } |
0 commit comments