-
Notifications
You must be signed in to change notification settings - Fork 0
/
cleanup.ts
156 lines (126 loc) · 5.28 KB
/
cleanup.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
* Copyright (c) 2024, Clay Chipps; Copyright (c) 2024, Salesforce.com, Inc.
* All rights reserved.
* Licensed under the BSD 3-Clause license.
* For full license text, see LICENSE.txt file in the repo root or https://opensource.org/licenses/BSD-3-Clause
*/
import { SfCommand, Flags } from '@salesforce/sf-plugins-core';
import { Messages, Logger } from '@salesforce/core';
import {
Package,
PackageSaveResult,
PackageVersion,
PackageVersionListOptions,
PackageVersionOptions,
} from '@salesforce/packaging';
Messages.importMessagesDirectoryFromMetaUrl(import.meta.url);
const messages = Messages.loadMessages('sf-chipps-package', 'chipps.package.version.cleanup');
export type PackageVersionCleanupResult = {
Error?: string;
Success: boolean;
SubscriberPackageVersionId: string;
};
export default class PackageVersionCleanup extends SfCommand<PackageVersionCleanupResult[]> {
public static readonly summary = messages.getMessage('summary');
public static readonly description = messages.getMessage('description');
public static readonly examples = messages.getMessages('examples');
// This is annoying, but the underlying Salesforce Packaging API expects you to be in a project context
// https://github.com/forcedotcom/packaging/blob/main/src/package/package.ts#L146C55-L146C55
public static readonly requiresProject = true;
public static readonly flags = {
'api-version': Flags.orgApiVersion(),
matcher: Flags.string({
summary: messages.getMessage('flags.matcher.summary'),
description: messages.getMessage('flags.matcher.description'),
char: 's',
required: true,
}),
package: Flags.string({
summary: messages.getMessage('flags.package.summary'),
description: messages.getMessage('flags.package.description'),
char: 'p',
required: true,
}),
'target-dev-hub': Flags.requiredHub(),
};
public async run(): Promise<PackageVersionCleanupResult[]> {
const log = await Logger.child(this.ctor.name);
const { flags } = await this.parse(PackageVersionCleanup);
// Create a connection to the org
const connection = flags['target-dev-hub']?.getConnection(flags['api-version']);
if (!connection) {
throw messages.createError('errors.connectionFailed');
}
const project = this.project;
const matcher = flags.matcher;
const matcherRegex = new RegExp(/^\d+\.\d+\.\d+$/);
const matcherValid = matcherRegex.test(matcher);
if (!matcherValid) {
throw messages.createError('errors.matcherFormatMismatch');
}
const matcherSplit = matcher.split('.');
const majorMatcher = matcherSplit.at(0);
const minorMatcher = matcherSplit.at(1);
const patchMatcher = matcherSplit.at(2);
log.info(`Major Matcher ${majorMatcher} Minor Matcher ${minorMatcher} Patch Matcher ${patchMatcher}`);
const packageVersionListOptions: PackageVersionListOptions = {
concise: false,
createdLastDays: undefined as unknown as number,
modifiedLastDays: undefined as unknown as number,
orderBy: 'MajorVersion, MinorVersion, PatchVersion, BuildNumber',
packages: [flags.package],
isReleased: false,
verbose: true,
};
this.spinner.start('Analyzing which package versions to delete...');
const packageVersions = await Package.listVersions(connection, project, packageVersionListOptions);
const targetVersions = packageVersions.filter(
(packageVersion) =>
packageVersion.IsReleased === false &&
packageVersion.MajorVersion.toString() === majorMatcher &&
packageVersion.MinorVersion.toString() === minorMatcher &&
packageVersion.PatchVersion.toString() === patchMatcher
);
const packageVersionDeletePromiseRequests: Array<Promise<PackageSaveResult>> = [];
targetVersions.forEach((targetVersion) => {
const packageVersionOptions: PackageVersionOptions = {
connection,
project,
idOrAlias: targetVersion.SubscriberPackageVersionId,
};
packageVersionDeletePromiseRequests.push(new PackageVersion(packageVersionOptions).delete());
});
const results: PackageVersionCleanupResult[] = [];
this.spinner.stop();
this.spinner.start('Deleting the package versions...');
const promiseResults = await Promise.allSettled(packageVersionDeletePromiseRequests);
promiseResults.forEach((promiseResult, index) => {
switch (promiseResult.status) {
case 'fulfilled':
results.push({
Success: promiseResult?.value?.success,
SubscriberPackageVersionId: targetVersions[index].SubscriberPackageVersionId,
});
break;
case 'rejected':
results.push({
Success: false,
Error: promiseResult.reason as string,
SubscriberPackageVersionId: targetVersions[index].SubscriberPackageVersionId,
});
break;
}
});
this.spinner.stop();
this.displayDeletionResults(results);
return results;
}
private displayDeletionResults(packageCleanupResults: PackageVersionCleanupResult[]): void {
this.styledHeader('Package Version Cleanup Results');
this.table(packageCleanupResults, {
SubscriberPackageVersionId: { header: 'PACKAGE VERSION ID' },
Success: { header: 'SUCCESS' },
Error: { header: 'ERROR' },
});
}
}