@gpc-cli/core 0.9.41 → 0.9.43

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { OutputFormat, ResolvedConfig, WebhookConfig } from '@gpc-cli/config';
2
2
  import { AuthClient } from '@gpc-cli/auth';
3
3
  import { GpcPlugin, PluginManifest, CommandEvent, CommandResult, PluginError, RequestEvent, ResponseEvent, PluginCommand } from '@gpc-cli/plugin-sdk';
4
- import { PlayApiClient, Track, ExternallyHostedApk, ExternallyHostedApkResponse, UploadProgressEvent, ResumableUploadOptions, Listing, ImageType, CountryAvailability, Image, AppDetails, Review, ReviewReplyResponse, Subscription, SubscriptionOffer, OffersListResponse, BasePlanMigratePricesRequest, InAppProduct, Order, SubscriptionDeferResponse, SubscriptionsV2DeferResponse, ProductPurchase, ProductPurchaseV2, SubscriptionPurchaseV2, VoidedPurchase, UsersApiClient, User, DeveloperPermission, Grant, MetricRow, ReportingDimension, ReportingAggregation, VitalsMetricSet, ReportingApiClient, AnomalyDetectionResponse, MetricSetResponse, ErrorIssuesResponse, ConvertRegionPricesResponse, ReportType, StatsDimension, ReportBucket, Testers, AppRecoveryTargeting, AppRecoveryAction, CreateAppRecoveryActionRequest, DataSafety, ExternalTransaction, ExternalTransactionRefund, DeviceTierConfig, OneTimeOffer, OneTimeProduct, OneTimeOffersListResponse, OneTimeProductsListResponse, GamesApiClient, Achievement, GameEvent, Leaderboard, EnterpriseApiClient, CustomApp, GeneratedApk, PurchaseOption, PurchaseOptionsListResponse } from '@gpc-cli/api';
4
+ import { PlayApiClient, EditCommitOptions, Track, ExternallyHostedApk, ExternallyHostedApkResponse, DeobfuscationFileType, UploadProgressEvent, ResumableUploadOptions, Listing, ImageType, CountryAvailability, Image, AppDetails, Review, ReviewReplyResponse, Subscription, SubscriptionOffer, OffersListResponse, BasePlanMigratePricesRequest, InAppProduct, Order, SubscriptionDeferResponse, SubscriptionsV2DeferResponse, ProductPurchase, ProductPurchaseV2, SubscriptionPurchaseV2, VoidedPurchase, UsersApiClient, User, DeveloperPermission, Grant, MetricRow, ReportingDimension, ReportingAggregation, VitalsMetricSet, ReportingApiClient, AnomalyDetectionResponse, MetricSetResponse, ErrorIssuesResponse, ConvertRegionPricesResponse, ReportType, StatsDimension, ReportBucket, Testers, AppRecoveryTargeting, AppRecoveryAction, CreateAppRecoveryActionRequest, DataSafety, ExternalTransaction, ExternalTransactionRefund, DeviceTierConfig, OneTimeOffer, OneTimeProduct, OneTimeOffersListResponse, OneTimeProductsListResponse, GamesApiClient, Achievement, GameEvent, Leaderboard, EnterpriseApiClient, CustomApp, GeneratedApk, PurchaseOption, PurchaseOptionsListResponse } from '@gpc-cli/api';
5
5
 
6
6
  declare class GpcError extends Error {
7
7
  readonly code: string;
@@ -153,10 +153,13 @@ declare function uploadRelease(client: PlayApiClient, packageName: string, fileP
153
153
  }[];
154
154
  releaseName?: string;
155
155
  mappingFile?: string;
156
+ mappingFileType?: DeobfuscationFileType;
156
157
  dryRun?: boolean;
157
158
  onProgress?: (uploaded: number, total: number) => void;
158
159
  onUploadProgress?: (event: UploadProgressEvent) => void;
159
160
  uploadOptions?: Pick<ResumableUploadOptions, "chunkSize" | "resumeSessionUri" | "maxResumeAttempts">;
161
+ deviceTierConfigId?: string;
162
+ commitOptions?: EditCommitOptions;
160
163
  }): Promise<UploadResult | DryRunUploadResult>;
161
164
  declare function getReleasesStatus(client: PlayApiClient, packageName: string, trackFilter?: string): Promise<ReleaseStatusResult[]>;
162
165
  declare function promoteRelease(client: PlayApiClient, packageName: string, fromTrack: string, toTrack: string, options?: {
@@ -166,11 +169,12 @@ declare function promoteRelease(client: PlayApiClient, packageName: string, from
166
169
  language: string;
167
170
  text: string;
168
171
  }[];
172
+ commitOptions?: EditCommitOptions;
169
173
  }): Promise<ReleaseStatusResult>;
170
- declare function updateRollout(client: PlayApiClient, packageName: string, track: string, action: "increase" | "halt" | "resume" | "complete", userFraction?: number): Promise<ReleaseStatusResult>;
174
+ declare function updateRollout(client: PlayApiClient, packageName: string, track: string, action: "increase" | "halt" | "resume" | "complete", userFraction?: number, commitOptions?: EditCommitOptions): Promise<ReleaseStatusResult>;
171
175
  declare function listTracks(client: PlayApiClient, packageName: string): Promise<Track[]>;
172
- declare function createTrack(client: PlayApiClient, packageName: string, trackName: string): Promise<Track>;
173
- declare function updateTrackConfig(client: PlayApiClient, packageName: string, trackName: string, config: Record<string, unknown>): Promise<Track>;
176
+ declare function createTrack(client: PlayApiClient, packageName: string, trackName: string, commitOptions?: EditCommitOptions): Promise<Track>;
177
+ declare function updateTrackConfig(client: PlayApiClient, packageName: string, trackName: string, config: Record<string, unknown>, commitOptions?: EditCommitOptions): Promise<Track>;
174
178
  /**
175
179
  * Fetch release notes from the latest active release on a given track.
176
180
  * Opens and discards an edit — read-only, no mutations.
@@ -189,7 +193,7 @@ declare function diffReleases(client: PlayApiClient, packageName: string, fromTr
189
193
  toTrack: string;
190
194
  diffs: ReleaseDiff[];
191
195
  }>;
192
- declare function uploadExternallyHosted(client: PlayApiClient, packageName: string, data: ExternallyHostedApk): Promise<ExternallyHostedApkResponse>;
196
+ declare function uploadExternallyHosted(client: PlayApiClient, packageName: string, data: ExternallyHostedApk, commitOptions?: EditCommitOptions): Promise<ExternallyHostedApkResponse>;
193
197
 
194
198
  interface ListingDiff {
195
199
  language: string;
@@ -255,8 +259,8 @@ interface DryRunResult {
255
259
  diffs: ListingDiff[];
256
260
  }
257
261
  declare function getListings(client: PlayApiClient, packageName: string, language?: string): Promise<Listing[]>;
258
- declare function updateListing(client: PlayApiClient, packageName: string, language: string, data: Partial<Omit<Listing, "language">>): Promise<Listing>;
259
- declare function deleteListing(client: PlayApiClient, packageName: string, language: string): Promise<void>;
262
+ declare function updateListing(client: PlayApiClient, packageName: string, language: string, data: Partial<Omit<Listing, "language">>, commitOptions?: EditCommitOptions): Promise<Listing>;
263
+ declare function deleteListing(client: PlayApiClient, packageName: string, language: string, commitOptions?: EditCommitOptions): Promise<void>;
260
264
  declare function pullListings(client: PlayApiClient, packageName: string, dir: string): Promise<ListingsResult>;
261
265
  /** Lint local listing directory against Play Store character limits (no API call). */
262
266
  declare function lintLocalListings(dir: string): Promise<ListingLintResult[]>;
@@ -275,10 +279,11 @@ declare function diffListingsEnhanced(client: PlayApiClient, packageName: string
275
279
  declare function pushListings(client: PlayApiClient, packageName: string, dir: string, options?: {
276
280
  dryRun?: boolean;
277
281
  force?: boolean;
282
+ commitOptions?: EditCommitOptions;
278
283
  }): Promise<PushResult | DryRunResult>;
279
284
  declare function listImages(client: PlayApiClient, packageName: string, language: string, imageType: ImageType): Promise<Image[]>;
280
- declare function uploadImage(client: PlayApiClient, packageName: string, language: string, imageType: ImageType, filePath: string): Promise<Image>;
281
- declare function deleteImage(client: PlayApiClient, packageName: string, language: string, imageType: ImageType, imageId: string): Promise<void>;
285
+ declare function uploadImage(client: PlayApiClient, packageName: string, language: string, imageType: ImageType, filePath: string, commitOptions?: EditCommitOptions): Promise<Image>;
286
+ declare function deleteImage(client: PlayApiClient, packageName: string, language: string, imageType: ImageType, imageId: string, commitOptions?: EditCommitOptions): Promise<void>;
282
287
  declare function diffListingsCommand(client: PlayApiClient, packageName: string, dir: string): Promise<ListingDiff[]>;
283
288
  declare function getCountryAvailability(client: PlayApiClient, packageName: string, track: string): Promise<CountryAvailability>;
284
289
  interface ExportImagesOptions {
@@ -291,7 +296,7 @@ interface ExportImagesSummary {
291
296
  totalSize: number;
292
297
  }
293
298
  declare function exportImages(client: PlayApiClient, packageName: string, dir: string, options?: ExportImagesOptions): Promise<ExportImagesSummary>;
294
- declare function updateAppDetails(client: PlayApiClient, packageName: string, details: Partial<AppDetails>): Promise<AppDetails>;
299
+ declare function updateAppDetails(client: PlayApiClient, packageName: string, details: Partial<AppDetails>, commitOptions?: EditCommitOptions): Promise<AppDetails>;
295
300
 
296
301
  interface FastlaneDetection {
297
302
  hasFastfile: boolean;
@@ -382,7 +387,10 @@ interface PublishOptions {
382
387
  notesDir?: string;
383
388
  releaseName?: string;
384
389
  mappingFile?: string;
390
+ mappingFileType?: DeobfuscationFileType;
391
+ deviceTierConfigId?: string;
385
392
  dryRun?: boolean;
393
+ commitOptions?: EditCommitOptions;
386
394
  }
387
395
  interface PublishResult {
388
396
  validation: ValidateResult;
@@ -670,9 +678,9 @@ declare function updateGrant(client: UsersApiClient, developerId: string, email:
670
678
  declare function deleteGrant(client: UsersApiClient, developerId: string, email: string, packageName: string): Promise<void>;
671
679
 
672
680
  declare function listTesters(client: PlayApiClient, packageName: string, track: string): Promise<Testers>;
673
- declare function addTesters(client: PlayApiClient, packageName: string, track: string, groupEmails: string[]): Promise<Testers>;
674
- declare function removeTesters(client: PlayApiClient, packageName: string, track: string, groupEmails: string[]): Promise<Testers>;
675
- declare function importTestersFromCsv(client: PlayApiClient, packageName: string, track: string, csvPath: string): Promise<{
681
+ declare function addTesters(client: PlayApiClient, packageName: string, track: string, groupEmails: string[], commitOptions?: EditCommitOptions): Promise<Testers>;
682
+ declare function removeTesters(client: PlayApiClient, packageName: string, track: string, groupEmails: string[], commitOptions?: EditCommitOptions): Promise<Testers>;
683
+ declare function importTestersFromCsv(client: PlayApiClient, packageName: string, track: string, csvPath: string, commitOptions?: EditCommitOptions): Promise<{
676
684
  added: number;
677
685
  testers: Testers;
678
686
  }>;
package/dist/index.js CHANGED
@@ -755,13 +755,14 @@ ${validation.errors.join("\n")}`,
755
755
  if (options.onUploadProgress) options.onUploadProgress(event);
756
756
  }
757
757
  };
758
- const bundle = isApk ? await client.apks.upload(packageName, edit.id, filePath, uploadOpts) : await client.bundles.upload(packageName, edit.id, filePath, uploadOpts);
758
+ const bundle = isApk ? await client.apks.upload(packageName, edit.id, filePath, uploadOpts) : await client.bundles.upload(packageName, edit.id, filePath, uploadOpts, options.deviceTierConfigId);
759
759
  if (options.mappingFile) {
760
760
  await client.deobfuscation.upload(
761
761
  packageName,
762
762
  edit.id,
763
763
  bundle.versionCode,
764
- options.mappingFile
764
+ options.mappingFile,
765
+ options.mappingFileType
765
766
  );
766
767
  }
767
768
  const release = {
@@ -772,8 +773,10 @@ ${validation.errors.join("\n")}`,
772
773
  ...options.releaseName && { name: options.releaseName }
773
774
  };
774
775
  await client.tracks.update(packageName, edit.id, options.track, release);
775
- await client.edits.validate(packageName, edit.id);
776
- await client.edits.commit(packageName, edit.id);
776
+ if (!options.commitOptions?.changesNotSentForReview) {
777
+ await client.edits.validate(packageName, edit.id);
778
+ }
779
+ await client.edits.commit(packageName, edit.id, options.commitOptions);
777
780
  return {
778
781
  versionCode: bundle.versionCode,
779
782
  track: options.track,
@@ -838,8 +841,10 @@ async function promoteRelease(client, packageName, fromTrack, toTrack, options)
838
841
  releaseNotes: options?.releaseNotes || currentRelease.releaseNotes || []
839
842
  };
840
843
  await client.tracks.update(packageName, edit.id, toTrack, release);
841
- await client.edits.validate(packageName, edit.id);
842
- await client.edits.commit(packageName, edit.id);
844
+ if (!options?.commitOptions?.changesNotSentForReview) {
845
+ await client.edits.validate(packageName, edit.id);
846
+ }
847
+ await client.edits.commit(packageName, edit.id, options?.commitOptions);
843
848
  return {
844
849
  track: toTrack,
845
850
  status: release.status,
@@ -848,7 +853,7 @@ async function promoteRelease(client, packageName, fromTrack, toTrack, options)
848
853
  };
849
854
  });
850
855
  }
851
- async function updateRollout(client, packageName, track, action, userFraction) {
856
+ async function updateRollout(client, packageName, track, action, userFraction, commitOptions) {
852
857
  const edit = await client.edits.insert(packageName);
853
858
  try {
854
859
  const trackData = await client.tracks.get(packageName, edit.id, track);
@@ -905,8 +910,10 @@ async function updateRollout(client, packageName, track, action, userFraction) {
905
910
  releaseNotes: currentRelease.releaseNotes || []
906
911
  };
907
912
  await client.tracks.update(packageName, edit.id, track, release);
908
- await client.edits.validate(packageName, edit.id);
909
- await client.edits.commit(packageName, edit.id);
913
+ if (!commitOptions?.changesNotSentForReview) {
914
+ await client.edits.validate(packageName, edit.id);
915
+ }
916
+ await client.edits.commit(packageName, edit.id, commitOptions);
910
917
  return {
911
918
  track,
912
919
  status: newStatus,
@@ -931,7 +938,7 @@ async function listTracks(client, packageName) {
931
938
  throw error;
932
939
  }
933
940
  }
934
- async function createTrack(client, packageName, trackName) {
941
+ async function createTrack(client, packageName, trackName, commitOptions) {
935
942
  if (!trackName || trackName.trim().length === 0) {
936
943
  throw new GpcError(
937
944
  "Track name must not be empty",
@@ -943,8 +950,10 @@ async function createTrack(client, packageName, trackName) {
943
950
  const edit = await client.edits.insert(packageName);
944
951
  try {
945
952
  const track = await client.tracks.create(packageName, edit.id, trackName);
946
- await client.edits.validate(packageName, edit.id);
947
- await client.edits.commit(packageName, edit.id);
953
+ if (!commitOptions?.changesNotSentForReview) {
954
+ await client.edits.validate(packageName, edit.id);
955
+ }
956
+ await client.edits.commit(packageName, edit.id, commitOptions);
948
957
  return track;
949
958
  } catch (error) {
950
959
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -952,7 +961,7 @@ async function createTrack(client, packageName, trackName) {
952
961
  throw error;
953
962
  }
954
963
  }
955
- async function updateTrackConfig(client, packageName, trackName, config) {
964
+ async function updateTrackConfig(client, packageName, trackName, config, commitOptions) {
956
965
  if (!trackName || trackName.trim().length === 0) {
957
966
  throw new GpcError(
958
967
  "Track name must not be empty",
@@ -977,8 +986,10 @@ async function updateTrackConfig(client, packageName, trackName, config) {
977
986
  release.name = config["name"];
978
987
  }
979
988
  const track = await client.tracks.update(packageName, edit.id, trackName, release);
980
- await client.edits.validate(packageName, edit.id);
981
- await client.edits.commit(packageName, edit.id);
989
+ if (!commitOptions?.changesNotSentForReview) {
990
+ await client.edits.validate(packageName, edit.id);
991
+ }
992
+ await client.edits.commit(packageName, edit.id, commitOptions);
982
993
  return track;
983
994
  } catch (error) {
984
995
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -1031,7 +1042,7 @@ async function diffReleases(client, packageName, fromTrack, toTrack) {
1031
1042
  throw error;
1032
1043
  }
1033
1044
  }
1034
- async function uploadExternallyHosted(client, packageName, data) {
1045
+ async function uploadExternallyHosted(client, packageName, data, commitOptions) {
1035
1046
  if (!data.externallyHostedUrl) {
1036
1047
  throw new GpcError(
1037
1048
  "externallyHostedUrl is required",
@@ -1051,8 +1062,10 @@ async function uploadExternallyHosted(client, packageName, data) {
1051
1062
  const edit = await client.edits.insert(packageName);
1052
1063
  try {
1053
1064
  const result = await client.apks.addExternallyHosted(packageName, edit.id, data);
1054
- await client.edits.validate(packageName, edit.id);
1055
- await client.edits.commit(packageName, edit.id);
1065
+ if (!commitOptions?.changesNotSentForReview) {
1066
+ await client.edits.validate(packageName, edit.id);
1067
+ }
1068
+ await client.edits.commit(packageName, edit.id, commitOptions);
1056
1069
  return result;
1057
1070
  } catch (error) {
1058
1071
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -1397,13 +1410,15 @@ async function getListings(client, packageName, language) {
1397
1410
  throw error;
1398
1411
  }
1399
1412
  }
1400
- async function updateListing(client, packageName, language, data) {
1413
+ async function updateListing(client, packageName, language, data, commitOptions) {
1401
1414
  validateLanguage(language);
1402
1415
  const edit = await client.edits.insert(packageName);
1403
1416
  try {
1404
1417
  const listing = await client.listings.patch(packageName, edit.id, language, data);
1405
- await client.edits.validate(packageName, edit.id);
1406
- await client.edits.commit(packageName, edit.id);
1418
+ if (!commitOptions?.changesNotSentForReview) {
1419
+ await client.edits.validate(packageName, edit.id);
1420
+ }
1421
+ await client.edits.commit(packageName, edit.id, commitOptions);
1407
1422
  return listing;
1408
1423
  } catch (error) {
1409
1424
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -1411,13 +1426,15 @@ async function updateListing(client, packageName, language, data) {
1411
1426
  throw error;
1412
1427
  }
1413
1428
  }
1414
- async function deleteListing(client, packageName, language) {
1429
+ async function deleteListing(client, packageName, language, commitOptions) {
1415
1430
  validateLanguage(language);
1416
1431
  const edit = await client.edits.insert(packageName);
1417
1432
  try {
1418
1433
  await client.listings.delete(packageName, edit.id, language);
1419
- await client.edits.validate(packageName, edit.id);
1420
- await client.edits.commit(packageName, edit.id);
1434
+ if (!commitOptions?.changesNotSentForReview) {
1435
+ await client.edits.validate(packageName, edit.id);
1436
+ }
1437
+ await client.edits.commit(packageName, edit.id, commitOptions);
1421
1438
  } catch (error) {
1422
1439
  await client.edits.delete(packageName, edit.id).catch(() => {
1423
1440
  });
@@ -1540,8 +1557,10 @@ ${details}`,
1540
1557
  const { language, ...data } = listing;
1541
1558
  await client.listings.update(packageName, edit.id, language, data);
1542
1559
  }
1543
- await client.edits.validate(packageName, edit.id);
1544
- await client.edits.commit(packageName, edit.id);
1560
+ if (!options?.commitOptions?.changesNotSentForReview) {
1561
+ await client.edits.validate(packageName, edit.id);
1562
+ }
1563
+ await client.edits.commit(packageName, edit.id, options?.commitOptions);
1545
1564
  return {
1546
1565
  updated: localListings.length,
1547
1566
  languages: localListings.map((l) => l.language)
@@ -1565,7 +1584,7 @@ async function listImages(client, packageName, language, imageType) {
1565
1584
  throw error;
1566
1585
  }
1567
1586
  }
1568
- async function uploadImage(client, packageName, language, imageType, filePath) {
1587
+ async function uploadImage(client, packageName, language, imageType, filePath, commitOptions) {
1569
1588
  validateLanguage(language);
1570
1589
  const imageCheck = await validateImage(filePath, imageType);
1571
1590
  if (!imageCheck.valid) {
@@ -1582,8 +1601,10 @@ async function uploadImage(client, packageName, language, imageType, filePath) {
1582
1601
  const edit = await client.edits.insert(packageName);
1583
1602
  try {
1584
1603
  const image = await client.images.upload(packageName, edit.id, language, imageType, filePath);
1585
- await client.edits.validate(packageName, edit.id);
1586
- await client.edits.commit(packageName, edit.id);
1604
+ if (!commitOptions?.changesNotSentForReview) {
1605
+ await client.edits.validate(packageName, edit.id);
1606
+ }
1607
+ await client.edits.commit(packageName, edit.id, commitOptions);
1587
1608
  return image;
1588
1609
  } catch (error) {
1589
1610
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -1591,13 +1612,15 @@ async function uploadImage(client, packageName, language, imageType, filePath) {
1591
1612
  throw error;
1592
1613
  }
1593
1614
  }
1594
- async function deleteImage(client, packageName, language, imageType, imageId) {
1615
+ async function deleteImage(client, packageName, language, imageType, imageId, commitOptions) {
1595
1616
  validateLanguage(language);
1596
1617
  const edit = await client.edits.insert(packageName);
1597
1618
  try {
1598
1619
  await client.images.delete(packageName, edit.id, language, imageType, imageId);
1599
- await client.edits.validate(packageName, edit.id);
1600
- await client.edits.commit(packageName, edit.id);
1620
+ if (!commitOptions?.changesNotSentForReview) {
1621
+ await client.edits.validate(packageName, edit.id);
1622
+ }
1623
+ await client.edits.commit(packageName, edit.id, commitOptions);
1601
1624
  } catch (error) {
1602
1625
  await client.edits.delete(packageName, edit.id).catch(() => {
1603
1626
  });
@@ -1706,12 +1729,14 @@ async function exportImages(client, packageName, dir, options) {
1706
1729
  throw error;
1707
1730
  }
1708
1731
  }
1709
- async function updateAppDetails(client, packageName, details) {
1732
+ async function updateAppDetails(client, packageName, details, commitOptions) {
1710
1733
  const edit = await client.edits.insert(packageName);
1711
1734
  try {
1712
1735
  const result = await client.details.patch(packageName, edit.id, details);
1713
- await client.edits.validate(packageName, edit.id);
1714
- await client.edits.commit(packageName, edit.id);
1736
+ if (!commitOptions?.changesNotSentForReview) {
1737
+ await client.edits.validate(packageName, edit.id);
1738
+ }
1739
+ await client.edits.commit(packageName, edit.id, commitOptions);
1715
1740
  return result;
1716
1741
  } catch (error) {
1717
1742
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -2186,7 +2211,10 @@ async function publish(client, packageName, filePath, options) {
2186
2211
  userFraction: options.rolloutPercent ? options.rolloutPercent / 100 : void 0,
2187
2212
  releaseNotes,
2188
2213
  releaseName: options.releaseName,
2189
- mappingFile: options.mappingFile
2214
+ mappingFile: options.mappingFile,
2215
+ mappingFileType: options.mappingFileType,
2216
+ deviceTierConfigId: options.deviceTierConfigId,
2217
+ commitOptions: options.commitOptions
2190
2218
  });
2191
2219
  return { validation, upload };
2192
2220
  }
@@ -3554,7 +3582,7 @@ async function listTesters(client, packageName, track) {
3554
3582
  await client.edits.delete(packageName, edit.id);
3555
3583
  }
3556
3584
  }
3557
- async function addTesters(client, packageName, track, groupEmails) {
3585
+ async function addTesters(client, packageName, track, groupEmails, commitOptions) {
3558
3586
  const edit = await client.edits.insert(packageName);
3559
3587
  try {
3560
3588
  const current = await client.testers.get(packageName, edit.id, track);
@@ -3565,8 +3593,10 @@ async function addTesters(client, packageName, track, groupEmails) {
3565
3593
  const updated = await client.testers.update(packageName, edit.id, track, {
3566
3594
  googleGroups: [...existing]
3567
3595
  });
3568
- await client.edits.validate(packageName, edit.id);
3569
- await client.edits.commit(packageName, edit.id);
3596
+ if (!commitOptions?.changesNotSentForReview) {
3597
+ await client.edits.validate(packageName, edit.id);
3598
+ }
3599
+ await client.edits.commit(packageName, edit.id, commitOptions);
3570
3600
  return updated;
3571
3601
  } catch (error) {
3572
3602
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -3574,7 +3604,7 @@ async function addTesters(client, packageName, track, groupEmails) {
3574
3604
  throw error;
3575
3605
  }
3576
3606
  }
3577
- async function removeTesters(client, packageName, track, groupEmails) {
3607
+ async function removeTesters(client, packageName, track, groupEmails, commitOptions) {
3578
3608
  const edit = await client.edits.insert(packageName);
3579
3609
  try {
3580
3610
  const current = await client.testers.get(packageName, edit.id, track);
@@ -3583,8 +3613,10 @@ async function removeTesters(client, packageName, track, groupEmails) {
3583
3613
  const updated = await client.testers.update(packageName, edit.id, track, {
3584
3614
  googleGroups: filtered
3585
3615
  });
3586
- await client.edits.validate(packageName, edit.id);
3587
- await client.edits.commit(packageName, edit.id);
3616
+ if (!commitOptions?.changesNotSentForReview) {
3617
+ await client.edits.validate(packageName, edit.id);
3618
+ }
3619
+ await client.edits.commit(packageName, edit.id, commitOptions);
3588
3620
  return updated;
3589
3621
  } catch (error) {
3590
3622
  await client.edits.delete(packageName, edit.id).catch(() => {
@@ -3592,7 +3624,7 @@ async function removeTesters(client, packageName, track, groupEmails) {
3592
3624
  throw error;
3593
3625
  }
3594
3626
  }
3595
- async function importTestersFromCsv(client, packageName, track, csvPath) {
3627
+ async function importTestersFromCsv(client, packageName, track, csvPath, commitOptions) {
3596
3628
  const content = await readFile5(csvPath, "utf-8");
3597
3629
  const emails = content.split(/[,\n\r]+/).map((e) => e.trim()).filter((e) => e.length > 0 && e.includes("@"));
3598
3630
  if (emails.length === 0) {
@@ -3603,7 +3635,7 @@ async function importTestersFromCsv(client, packageName, track, csvPath) {
3603
3635
  "The CSV file must contain email addresses separated by commas or newlines. Each email must contain an @ symbol."
3604
3636
  );
3605
3637
  }
3606
- const testers = await addTesters(client, packageName, track, emails);
3638
+ const testers = await addTesters(client, packageName, track, emails, commitOptions);
3607
3639
  return { added: emails.length, testers };
3608
3640
  }
3609
3641