@pilatos/bitbucket-cli 1.12.0 → 1.13.0

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.
Files changed (2) hide show
  1. package/dist/index.js +493 -71
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -14276,6 +14276,10 @@ var ServiceTokens = {
14276
14276
  ListReposCommand: "ListReposCommand",
14277
14277
  ViewRepoCommand: "ViewRepoCommand",
14278
14278
  DeleteRepoCommand: "DeleteRepoCommand",
14279
+ ListDefaultReviewersCommand: "ListDefaultReviewersCommand",
14280
+ AddDefaultReviewerCommand: "AddDefaultReviewerCommand",
14281
+ RemoveDefaultReviewerCommand: "RemoveDefaultReviewerCommand",
14282
+ DefaultReviewerService: "DefaultReviewerService",
14279
14283
  CreatePRCommand: "CreatePRCommand",
14280
14284
  ListPRsCommand: "ListPRsCommand",
14281
14285
  ViewPRCommand: "ViewPRCommand",
@@ -15293,13 +15297,15 @@ class OutputService {
15293
15297
  var SETTABLE_CONFIG_KEYS = [
15294
15298
  "defaultWorkspace",
15295
15299
  "skipVersionCheck",
15296
- "versionCheckInterval"
15300
+ "versionCheckInterval",
15301
+ "prCreateIncludeDefaultReviewers"
15297
15302
  ];
15298
15303
  var READABLE_CONFIG_KEYS = [
15299
15304
  "username",
15300
15305
  "defaultWorkspace",
15301
15306
  "skipVersionCheck",
15302
- "versionCheckInterval"
15307
+ "versionCheckInterval",
15308
+ "prCreateIncludeDefaultReviewers"
15303
15309
  ];
15304
15310
  function isSettableConfigKey(key) {
15305
15311
  return SETTABLE_CONFIG_KEYS.includes(key);
@@ -15354,9 +15360,20 @@ function parseSettableConfigValue(key, value) {
15354
15360
  }
15355
15361
  return parsed;
15356
15362
  }
15363
+ case "prCreateIncludeDefaultReviewers": {
15364
+ const parsed = parseBooleanLiteral(value);
15365
+ if (parsed === undefined) {
15366
+ throw new BBError({
15367
+ code: 5002 /* VALIDATION_INVALID */,
15368
+ message: "Invalid value for 'prCreateIncludeDefaultReviewers'. Expected 'true' or 'false'.",
15369
+ context: { key, value }
15370
+ });
15371
+ }
15372
+ return parsed;
15373
+ }
15357
15374
  }
15358
15375
  }
15359
- function coerceSkipVersionCheckValue(value) {
15376
+ function coerceBooleanConfigValue(value) {
15360
15377
  if (typeof value === "boolean") {
15361
15378
  return value;
15362
15379
  }
@@ -15365,6 +15382,7 @@ function coerceSkipVersionCheckValue(value) {
15365
15382
  }
15366
15383
  return;
15367
15384
  }
15385
+ var coerceSkipVersionCheckValue = coerceBooleanConfigValue;
15368
15386
  function coerceVersionCheckIntervalValue(value) {
15369
15387
  if (typeof value === "number") {
15370
15388
  if (!Number.isSafeInteger(value) || value < 1) {
@@ -15383,7 +15401,8 @@ function normalizeReadableConfigValue(key, value) {
15383
15401
  }
15384
15402
  switch (key) {
15385
15403
  case "skipVersionCheck":
15386
- return coerceSkipVersionCheckValue(value);
15404
+ case "prCreateIncludeDefaultReviewers":
15405
+ return coerceBooleanConfigValue(value);
15387
15406
  case "versionCheckInterval":
15388
15407
  return coerceVersionCheckIntervalValue(value);
15389
15408
  case "username":
@@ -18911,6 +18930,37 @@ var BASE_URL = "https://api.bitbucket.org/2.0";
18911
18930
  var MAX_RETRIES = 3;
18912
18931
  var BASE_DELAY_MS = 1000;
18913
18932
  var RETRYABLE_STATUS_CODES = new Set([429, 502, 503, 504]);
18933
+ var SENSITIVE_KEYS = new Set([
18934
+ "access_token",
18935
+ "refresh_token",
18936
+ "token",
18937
+ "id_token",
18938
+ "client_secret",
18939
+ "password",
18940
+ "authorization"
18941
+ ]);
18942
+ var REDACTED = "[REDACTED]";
18943
+ function redactSensitive(value, seen = new WeakSet) {
18944
+ if (value === null || typeof value !== "object") {
18945
+ return value;
18946
+ }
18947
+ if (seen.has(value)) {
18948
+ return "[Circular]";
18949
+ }
18950
+ seen.add(value);
18951
+ if (Array.isArray(value)) {
18952
+ return value.map((item) => redactSensitive(item, seen));
18953
+ }
18954
+ const result = {};
18955
+ for (const [key, val] of Object.entries(value)) {
18956
+ if (SENSITIVE_KEYS.has(key.toLowerCase())) {
18957
+ result[key] = REDACTED;
18958
+ } else {
18959
+ result[key] = redactSensitive(val, seen);
18960
+ }
18961
+ }
18962
+ return result;
18963
+ }
18914
18964
  function getRetryDelay(error, attempt) {
18915
18965
  if (error.response?.status === 429) {
18916
18966
  const retryAfter = error.response.headers["retry-after"];
@@ -18952,14 +19002,14 @@ function createApiClient(configService, oauthService) {
18952
19002
  instance.interceptors.response.use((response) => {
18953
19003
  if (process.env.DEBUG === "true") {
18954
19004
  console.debug(`[HTTP] Response: ${response.status}`);
18955
- console.debug(`[HTTP] Response Body:`, JSON.stringify(response.data, null, 2));
19005
+ console.debug(`[HTTP] Response Body:`, JSON.stringify(redactSensitive(response.data), null, 2));
18956
19006
  }
18957
19007
  return response;
18958
19008
  }, async (error) => {
18959
19009
  if (process.env.DEBUG === "true") {
18960
19010
  console.debug(`[HTTP] Error:`, error.message);
18961
19011
  if (error.response) {
18962
- console.debug(`[HTTP] Error Response Body:`, JSON.stringify(error.response.data, null, 2));
19012
+ console.debug(`[HTTP] Error Response Body:`, JSON.stringify(redactSensitive(error.response.data), null, 2));
18963
19013
  }
18964
19014
  }
18965
19015
  if (error.response?.status === 401 && oauthService) {
@@ -19546,6 +19596,128 @@ async function updatePullRequestReviewers(pullrequestsApi, repoContext, prId, tr
19546
19596
  });
19547
19597
  return response.data;
19548
19598
  }
19599
+ // src/services/pagination.ts
19600
+ var DEFAULT_LIMIT = 25;
19601
+ var MAX_PAGE_LENGTH = 50;
19602
+ function parseLimit(limit, fallback = DEFAULT_LIMIT) {
19603
+ if (!limit) {
19604
+ return fallback;
19605
+ }
19606
+ const parsed = Number.parseInt(limit, 10);
19607
+ if (Number.isNaN(parsed) || parsed <= 0) {
19608
+ return fallback;
19609
+ }
19610
+ return parsed;
19611
+ }
19612
+ async function collectPages(options) {
19613
+ const { fetchPage, shouldInclude } = options;
19614
+ const limit = Math.max(0, options.limit);
19615
+ if (limit === 0) {
19616
+ return [];
19617
+ }
19618
+ const requestedPageSize = options.pageSize ?? limit;
19619
+ const pagelen = Math.max(1, Math.min(requestedPageSize, MAX_PAGE_LENGTH));
19620
+ const items = [];
19621
+ let page = 1;
19622
+ while (items.length < limit) {
19623
+ const data = await fetchPage(page, pagelen);
19624
+ const pageValues = data.values ? Array.from(data.values) : [];
19625
+ if (pageValues.length === 0) {
19626
+ break;
19627
+ }
19628
+ for (const value of pageValues) {
19629
+ if (shouldInclude && !shouldInclude(value)) {
19630
+ continue;
19631
+ }
19632
+ items.push(value);
19633
+ if (items.length >= limit) {
19634
+ return items;
19635
+ }
19636
+ }
19637
+ if (!data.next) {
19638
+ break;
19639
+ }
19640
+ page += 1;
19641
+ }
19642
+ return items;
19643
+ }
19644
+
19645
+ // src/services/default-reviewer.service.ts
19646
+ var LIST_LIMIT = 500;
19647
+
19648
+ class DefaultReviewerService {
19649
+ pullrequestsApi;
19650
+ constructor(pullrequestsApi) {
19651
+ this.pullrequestsApi = pullrequestsApi;
19652
+ }
19653
+ async list(repo, mode = "effective") {
19654
+ if (mode === "effective") {
19655
+ return this.listEffective(repo);
19656
+ }
19657
+ return this.listDirect(repo);
19658
+ }
19659
+ async add(repo, username) {
19660
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugDefaultReviewersTargetUsernamePut({
19661
+ workspace: repo.workspace,
19662
+ repoSlug: repo.repoSlug,
19663
+ targetUsername: username
19664
+ }, { data: {} });
19665
+ return accountToEntry(response.data);
19666
+ }
19667
+ async remove(repo, username) {
19668
+ await this.pullrequestsApi.repositoriesWorkspaceRepoSlugDefaultReviewersTargetUsernameDelete({
19669
+ workspace: repo.workspace,
19670
+ repoSlug: repo.repoSlug,
19671
+ targetUsername: username
19672
+ });
19673
+ }
19674
+ async listDirect(repo) {
19675
+ const accounts = await collectPages({
19676
+ limit: LIST_LIMIT,
19677
+ fetchPage: async (page, pagelen) => {
19678
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugDefaultReviewersGet({
19679
+ workspace: repo.workspace,
19680
+ repoSlug: repo.repoSlug
19681
+ }, { params: { page, pagelen } });
19682
+ return response.data;
19683
+ }
19684
+ });
19685
+ return accounts.map((account) => accountToEntry(account));
19686
+ }
19687
+ async listEffective(repo) {
19688
+ const entries = await collectPages({
19689
+ limit: LIST_LIMIT,
19690
+ fetchPage: async (page, pagelen) => {
19691
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugEffectiveDefaultReviewersGet({
19692
+ workspace: repo.workspace,
19693
+ repoSlug: repo.repoSlug
19694
+ }, { params: { page, pagelen } });
19695
+ return response.data;
19696
+ }
19697
+ });
19698
+ const mapped = [];
19699
+ for (const entry of entries) {
19700
+ const user = entry.user;
19701
+ if (!user?.uuid) {
19702
+ continue;
19703
+ }
19704
+ mapped.push({
19705
+ ...accountToEntry(user),
19706
+ reviewerType: entry.reviewer_type
19707
+ });
19708
+ }
19709
+ return mapped;
19710
+ }
19711
+ }
19712
+ function accountToEntry(account) {
19713
+ const asUser = account;
19714
+ return {
19715
+ uuid: account.uuid ?? "",
19716
+ accountId: asUser.account_id,
19717
+ displayName: account.display_name,
19718
+ nickname: asUser.nickname
19719
+ };
19720
+ }
19549
19721
  // src/bootstrap.ts
19550
19722
  import { createRequire } from "module";
19551
19723
 
@@ -19644,6 +19816,14 @@ var createRequestFunction = function(axiosArgs, globalAxios, BASE_PATH2, configu
19644
19816
  };
19645
19817
 
19646
19818
  // src/generated/api.ts
19819
+ var PullrequestMergeParametersMergeStrategyEnum = {
19820
+ MergeCommit: "merge_commit",
19821
+ Squash: "squash",
19822
+ FastForward: "fast_forward",
19823
+ SquashFastForward: "squash_fast_forward",
19824
+ RebaseFastForward: "rebase_fast_forward",
19825
+ RebaseMerge: "rebase_merge"
19826
+ };
19647
19827
  var CommitStatusesApiAxiosParamCreator = function(configuration) {
19648
19828
  return {
19649
19829
  repositoriesWorkspaceRepoSlugCommitCommitStatusesBuildKeyGet: async (commit, key, repoSlug, workspace, options = {}) => {
@@ -23929,52 +24109,6 @@ class CreateRepoCommand extends BaseCommand {
23929
24109
  }
23930
24110
  }
23931
24111
 
23932
- // src/services/pagination.ts
23933
- var DEFAULT_LIMIT = 25;
23934
- var MAX_PAGE_LENGTH = 50;
23935
- function parseLimit(limit, fallback = DEFAULT_LIMIT) {
23936
- if (!limit) {
23937
- return fallback;
23938
- }
23939
- const parsed = Number.parseInt(limit, 10);
23940
- if (Number.isNaN(parsed) || parsed <= 0) {
23941
- return fallback;
23942
- }
23943
- return parsed;
23944
- }
23945
- async function collectPages(options) {
23946
- const { fetchPage, shouldInclude } = options;
23947
- const limit = Math.max(0, options.limit);
23948
- if (limit === 0) {
23949
- return [];
23950
- }
23951
- const requestedPageSize = options.pageSize ?? limit;
23952
- const pagelen = Math.max(1, Math.min(requestedPageSize, MAX_PAGE_LENGTH));
23953
- const items = [];
23954
- let page = 1;
23955
- while (items.length < limit) {
23956
- const data = await fetchPage(page, pagelen);
23957
- const pageValues = data.values ? Array.from(data.values) : [];
23958
- if (pageValues.length === 0) {
23959
- break;
23960
- }
23961
- for (const value of pageValues) {
23962
- if (shouldInclude && !shouldInclude(value)) {
23963
- continue;
23964
- }
23965
- items.push(value);
23966
- if (items.length >= limit) {
23967
- return items;
23968
- }
23969
- }
23970
- if (!data.next) {
23971
- break;
23972
- }
23973
- page += 1;
23974
- }
23975
- return items;
23976
- }
23977
-
23978
24112
  // src/commands/repo/list.command.ts
23979
24113
  class ListReposCommand extends BaseCommand {
23980
24114
  repositoriesApi;
@@ -24123,18 +24257,148 @@ class DeleteRepoCommand extends BaseCommand {
24123
24257
  }
24124
24258
  }
24125
24259
 
24260
+ // src/commands/repo/default-reviewers.list.command.ts
24261
+ class ListDefaultReviewersCommand extends BaseCommand {
24262
+ defaultReviewerService;
24263
+ contextService;
24264
+ name = "default-reviewers.list";
24265
+ description = "List default reviewers for a repository";
24266
+ constructor(defaultReviewerService, contextService, output) {
24267
+ super(output);
24268
+ this.defaultReviewerService = defaultReviewerService;
24269
+ this.contextService = contextService;
24270
+ }
24271
+ async execute(options, context) {
24272
+ const repoContext = await this.contextService.requireRepoContext({
24273
+ ...context.globalOptions,
24274
+ ...options
24275
+ });
24276
+ const mode = options.repoOnly ? "direct" : "effective";
24277
+ const reviewers = await this.defaultReviewerService.list(repoContext, mode);
24278
+ if (context.globalOptions.json) {
24279
+ this.output.json({
24280
+ workspace: repoContext.workspace,
24281
+ repoSlug: repoContext.repoSlug,
24282
+ mode,
24283
+ count: reviewers.length,
24284
+ reviewers
24285
+ });
24286
+ return;
24287
+ }
24288
+ if (reviewers.length === 0) {
24289
+ this.output.info("No default reviewers configured for this repository");
24290
+ return;
24291
+ }
24292
+ if (mode === "effective") {
24293
+ this.output.table(["Display Name", "Nickname", "Source"], reviewers.map((r) => [
24294
+ r.displayName ?? "Unknown",
24295
+ r.nickname ?? "",
24296
+ r.reviewerType ?? ""
24297
+ ]));
24298
+ } else {
24299
+ this.output.table(["Display Name", "Nickname"], reviewers.map((r) => [r.displayName ?? "Unknown", r.nickname ?? ""]));
24300
+ }
24301
+ }
24302
+ }
24303
+
24304
+ // src/commands/repo/default-reviewers.add.command.ts
24305
+ class AddDefaultReviewerCommand extends BaseCommand {
24306
+ defaultReviewerService;
24307
+ usersApi;
24308
+ contextService;
24309
+ name = "default-reviewers.add";
24310
+ description = "Add a default reviewer to a repository";
24311
+ constructor(defaultReviewerService, usersApi, contextService, output) {
24312
+ super(output);
24313
+ this.defaultReviewerService = defaultReviewerService;
24314
+ this.usersApi = usersApi;
24315
+ this.contextService = contextService;
24316
+ }
24317
+ async execute(options, context) {
24318
+ const repoContext = await this.contextService.requireRepoContext({
24319
+ ...context.globalOptions,
24320
+ ...options
24321
+ });
24322
+ const userResponse = await this.usersApi.usersSelectedUserGet({
24323
+ selectedUser: options.username
24324
+ });
24325
+ const user = userResponse.data;
24326
+ const identifier = user.uuid ?? options.username;
24327
+ const entry = await this.defaultReviewerService.add(repoContext, identifier);
24328
+ if (context.globalOptions.json) {
24329
+ this.output.json({
24330
+ success: true,
24331
+ workspace: repoContext.workspace,
24332
+ repoSlug: repoContext.repoSlug,
24333
+ reviewer: entry
24334
+ });
24335
+ return;
24336
+ }
24337
+ this.output.success(`Added ${entry.displayName ?? user.display_name ?? options.username} as a default reviewer for ${repoContext.workspace}/${repoContext.repoSlug}`);
24338
+ }
24339
+ }
24340
+
24341
+ // src/commands/repo/default-reviewers.remove.command.ts
24342
+ class RemoveDefaultReviewerCommand extends BaseCommand {
24343
+ defaultReviewerService;
24344
+ usersApi;
24345
+ contextService;
24346
+ name = "default-reviewers.remove";
24347
+ description = "Remove a default reviewer from a repository";
24348
+ constructor(defaultReviewerService, usersApi, contextService, output) {
24349
+ super(output);
24350
+ this.defaultReviewerService = defaultReviewerService;
24351
+ this.usersApi = usersApi;
24352
+ this.contextService = contextService;
24353
+ }
24354
+ async execute(options, context) {
24355
+ const repoContext = await this.contextService.requireRepoContext({
24356
+ ...context.globalOptions,
24357
+ ...options
24358
+ });
24359
+ if (!options.yes) {
24360
+ throw new BBError({
24361
+ code: 5001 /* VALIDATION_REQUIRED */,
24362
+ message: `This will remove ${options.username} from the default reviewers of ` + `${repoContext.workspace}/${repoContext.repoSlug}.
24363
+ ` + "Use --yes to confirm."
24364
+ });
24365
+ }
24366
+ const userResponse = await this.usersApi.usersSelectedUserGet({
24367
+ selectedUser: options.username
24368
+ });
24369
+ const identifier = userResponse.data.uuid ?? options.username;
24370
+ await this.defaultReviewerService.remove(repoContext, identifier);
24371
+ if (context.globalOptions.json) {
24372
+ this.output.json({
24373
+ success: true,
24374
+ workspace: repoContext.workspace,
24375
+ repoSlug: repoContext.repoSlug,
24376
+ username: options.username
24377
+ });
24378
+ return;
24379
+ }
24380
+ this.output.success(`Removed ${options.username} from default reviewers of ${repoContext.workspace}/${repoContext.repoSlug}`);
24381
+ }
24382
+ }
24383
+
24126
24384
  // src/commands/pr/create.command.ts
24127
24385
  class CreatePRCommand extends BaseCommand {
24128
24386
  pullrequestsApi;
24387
+ usersApi;
24129
24388
  contextService;
24130
24389
  gitService;
24390
+ defaultReviewerService;
24391
+ configService;
24131
24392
  name = "create";
24132
24393
  description = "Create a pull request";
24133
- constructor(pullrequestsApi, contextService, gitService, output) {
24394
+ constructor(pullrequestsApi, usersApi, contextService, gitService, defaultReviewerService, configService, output) {
24134
24395
  super(output);
24135
24396
  this.pullrequestsApi = pullrequestsApi;
24397
+ this.usersApi = usersApi;
24136
24398
  this.contextService = contextService;
24137
24399
  this.gitService = gitService;
24400
+ this.defaultReviewerService = defaultReviewerService;
24401
+ this.configService = configService;
24138
24402
  }
24139
24403
  async execute(options, context) {
24140
24404
  if (!options.title) {
@@ -24152,6 +24416,9 @@ class CreatePRCommand extends BaseCommand {
24152
24416
  sourceBranch = await this.gitService.getCurrentBranch();
24153
24417
  }
24154
24418
  const destinationBranch = options.destination || "main";
24419
+ const includeDefaults = await this.shouldIncludeDefaults(options);
24420
+ const explicitUsernames = options.reviewer ?? [];
24421
+ const reviewers = await this.resolveReviewers(repoContext, includeDefaults, explicitUsernames);
24155
24422
  const request = {
24156
24423
  type: "pullrequest",
24157
24424
  title: options.title,
@@ -24171,6 +24438,9 @@ class CreatePRCommand extends BaseCommand {
24171
24438
  if (options.draft) {
24172
24439
  request.draft = true;
24173
24440
  }
24441
+ if (reviewers.length > 0) {
24442
+ request.reviewers = reviewers.map((r) => ({ type: "user", uuid: r.uuid }));
24443
+ }
24174
24444
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPost({
24175
24445
  workspace: repoContext.workspace,
24176
24446
  repoSlug: repoContext.repoSlug,
@@ -24185,6 +24455,66 @@ class CreatePRCommand extends BaseCommand {
24185
24455
  this.output.success(`Created pull request #${pr.id}`);
24186
24456
  this.output.text(` ${this.output.dim("Title:")} ${pr.title}`);
24187
24457
  this.output.text(` ${this.output.dim("URL:")} ${links?.html?.href}`);
24458
+ if (reviewers.length > 0) {
24459
+ const labels = reviewers.map((r) => r.label).join(", ");
24460
+ this.output.text(` ${this.output.dim("Reviewers:")} ${labels}`);
24461
+ }
24462
+ }
24463
+ async shouldIncludeDefaults(options) {
24464
+ if (typeof options.defaultReviewers === "boolean") {
24465
+ return options.defaultReviewers;
24466
+ }
24467
+ const config = await this.configService.getConfig();
24468
+ return config.prCreateIncludeDefaultReviewers === true;
24469
+ }
24470
+ async resolveReviewers(repoContext, includeDefaults, explicitUsernames) {
24471
+ const byUuid = new Map;
24472
+ if (includeDefaults) {
24473
+ try {
24474
+ const defaults2 = await this.defaultReviewerService.list(repoContext, "effective");
24475
+ for (const entry of defaults2) {
24476
+ if (!entry.uuid) {
24477
+ continue;
24478
+ }
24479
+ byUuid.set(entry.uuid, {
24480
+ uuid: entry.uuid,
24481
+ label: entry.displayName ?? entry.nickname ?? entry.uuid
24482
+ });
24483
+ }
24484
+ } catch (error) {
24485
+ const message = error instanceof Error ? error.message : String(error);
24486
+ this.output.warning(`Could not fetch default reviewers: ${message}. Continuing without them.`);
24487
+ }
24488
+ }
24489
+ for (const username of explicitUsernames) {
24490
+ const userResponse = await this.usersApi.usersSelectedUserGet({
24491
+ selectedUser: username
24492
+ });
24493
+ const user = userResponse.data;
24494
+ if (!user.uuid) {
24495
+ continue;
24496
+ }
24497
+ byUuid.set(user.uuid, {
24498
+ uuid: user.uuid,
24499
+ label: user.display_name ?? username
24500
+ });
24501
+ }
24502
+ if (byUuid.size === 0) {
24503
+ return [];
24504
+ }
24505
+ const authorUuid = await this.getAuthorUuid();
24506
+ if (authorUuid) {
24507
+ byUuid.delete(authorUuid);
24508
+ }
24509
+ return Array.from(byUuid.values());
24510
+ }
24511
+ async getAuthorUuid() {
24512
+ try {
24513
+ const response = await this.usersApi.userGet();
24514
+ return response.data.uuid;
24515
+ } catch {
24516
+ return;
24517
+ }
24188
24518
  }
24189
24519
  }
24190
24520
 
@@ -24295,7 +24625,7 @@ class ViewPRCommand extends BaseCommand {
24295
24625
  ...context.globalOptions,
24296
24626
  ...options
24297
24627
  });
24298
- const prId = Number.parseInt(options.id, 10);
24628
+ const prId = this.parseIntOption(options.id, "id");
24299
24629
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
24300
24630
  workspace: repoContext.workspace,
24301
24631
  repoSlug: repoContext.repoSlug,
@@ -24505,6 +24835,8 @@ class EditPRCommand extends BaseCommand {
24505
24835
  }
24506
24836
 
24507
24837
  // src/commands/pr/merge.command.ts
24838
+ var VALID_STRATEGIES = Object.values(PullrequestMergeParametersMergeStrategyEnum);
24839
+
24508
24840
  class MergePRCommand extends BaseCommand {
24509
24841
  pullrequestsApi;
24510
24842
  contextService;
@@ -24520,7 +24852,7 @@ class MergePRCommand extends BaseCommand {
24520
24852
  ...context.globalOptions,
24521
24853
  ...options
24522
24854
  });
24523
- const prId = Number.parseInt(options.id, 10);
24855
+ const prId = this.parseIntOption(options.id, "id");
24524
24856
  const request = {
24525
24857
  type: "pullrequest_merge_parameters"
24526
24858
  };
@@ -24531,7 +24863,7 @@ class MergePRCommand extends BaseCommand {
24531
24863
  request.close_source_branch = true;
24532
24864
  }
24533
24865
  if (options.strategy) {
24534
- request.merge_strategy = options.strategy;
24866
+ request.merge_strategy = this.parseEnumOption(options.strategy, "strategy", VALID_STRATEGIES);
24535
24867
  }
24536
24868
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdMergePost({
24537
24869
  workspace: repoContext.workspace,
@@ -24962,6 +25294,16 @@ class DiffPRCommand extends BaseCommand {
24962
25294
  }
24963
25295
 
24964
25296
  // src/commands/pr/activity.command.ts
25297
+ var VALID_ACTIVITY_TYPES = [
25298
+ "comment",
25299
+ "approval",
25300
+ "changes_requested",
25301
+ "merge",
25302
+ "decline",
25303
+ "commit",
25304
+ "update"
25305
+ ];
25306
+
24965
25307
  class ActivityPRCommand extends BaseCommand {
24966
25308
  pullrequestsApi;
24967
25309
  contextService;
@@ -24977,7 +25319,7 @@ class ActivityPRCommand extends BaseCommand {
24977
25319
  ...context.globalOptions,
24978
25320
  ...options
24979
25321
  });
24980
- const prId = Number.parseInt(options.id, 10);
25322
+ const prId = this.parseIntOption(options.id, "id");
24981
25323
  const filterTypes = this.parseTypeFilter(options.type);
24982
25324
  const limit = parseLimit(options.limit);
24983
25325
  const activities = await collectPages({
@@ -25035,7 +25377,16 @@ class ActivityPRCommand extends BaseCommand {
25035
25377
  if (!typeOption) {
25036
25378
  return [];
25037
25379
  }
25038
- return typeOption.split(",").map((type) => type.trim().toLowerCase()).filter((type) => type.length > 0);
25380
+ const requested = typeOption.split(",").map((type) => type.trim().toLowerCase()).filter((type) => type.length > 0);
25381
+ const invalid = requested.filter((type) => !VALID_ACTIVITY_TYPES.includes(type));
25382
+ if (invalid.length > 0) {
25383
+ throw new BBError({
25384
+ code: 5002 /* VALIDATION_INVALID */,
25385
+ message: `--type must be one of: ${VALID_ACTIVITY_TYPES.join(", ")}`,
25386
+ context: { invalid }
25387
+ });
25388
+ }
25389
+ return requested;
25039
25390
  }
25040
25391
  getActivityType(activity) {
25041
25392
  if (activity.comment) {
@@ -25328,6 +25679,13 @@ class DeleteCommentPRCommand extends BaseCommand {
25328
25679
  });
25329
25680
  const prId = this.parseIntOption(options.prId, "pr-id");
25330
25681
  const commentId = this.parseIntOption(options.commentId, "comment-id");
25682
+ if (!options.yes) {
25683
+ throw new BBError({
25684
+ code: 5001 /* VALIDATION_REQUIRED */,
25685
+ message: `This will permanently delete comment #${commentId} on PR #${prId}.
25686
+ ` + "Use --yes to confirm deletion."
25687
+ });
25688
+ }
25331
25689
  await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdCommentsCommentIdDelete({
25332
25690
  workspace: repoContext.workspace,
25333
25691
  repoSlug: repoContext.repoSlug,
@@ -25487,7 +25845,7 @@ class ChecksPRCommand extends BaseCommand {
25487
25845
  ...context.globalOptions,
25488
25846
  ...options
25489
25847
  });
25490
- const prId = Number.parseInt(options.id, 10);
25848
+ const prId = this.parseIntOption(options.id, "id");
25491
25849
  const response = await this.commitStatusesApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdStatusesGet({
25492
25850
  workspace: repoContext.workspace,
25493
25851
  repoSlug: repoContext.repoSlug,
@@ -25496,8 +25854,7 @@ class ChecksPRCommand extends BaseCommand {
25496
25854
  const data = response.data;
25497
25855
  const statuses = data?.values ? Array.from(data.values) : [];
25498
25856
  const summary = this.getSummary(statuses);
25499
- const useJson = options.json || context.globalOptions.json;
25500
- if (useJson) {
25857
+ if (context.globalOptions.json) {
25501
25858
  this.output.json({
25502
25859
  pullRequestId: prId,
25503
25860
  workspace: repoContext.workspace,
@@ -26233,7 +26590,7 @@ class ListConfigCommand extends BaseCommand {
26233
26590
  if (config.apiToken) {
26234
26591
  displayConfig.apiToken = "********";
26235
26592
  }
26236
- const skipVersionCheck = coerceSkipVersionCheckValue(config.skipVersionCheck);
26593
+ const skipVersionCheck = coerceBooleanConfigValue(config.skipVersionCheck);
26237
26594
  if (skipVersionCheck !== undefined) {
26238
26595
  displayConfig.skipVersionCheck = skipVersionCheck;
26239
26596
  }
@@ -26241,6 +26598,10 @@ class ListConfigCommand extends BaseCommand {
26241
26598
  if (versionCheckInterval !== undefined) {
26242
26599
  displayConfig.versionCheckInterval = versionCheckInterval;
26243
26600
  }
26601
+ const prCreateIncludeDefaultReviewers = coerceBooleanConfigValue(config.prCreateIncludeDefaultReviewers);
26602
+ if (prCreateIncludeDefaultReviewers !== undefined) {
26603
+ displayConfig.prCreateIncludeDefaultReviewers = prCreateIncludeDefaultReviewers;
26604
+ }
26244
26605
  if (context.globalOptions.json) {
26245
26606
  this.output.json({
26246
26607
  configPath: this.configService.getConfigPath(),
@@ -26443,12 +26804,39 @@ function bootstrap(options = {}) {
26443
26804
  const output = container.resolve(ServiceTokens.OutputService);
26444
26805
  return new DeleteRepoCommand(repositoriesApi, contextService, output);
26445
26806
  });
26807
+ container.register(ServiceTokens.DefaultReviewerService, () => {
26808
+ const pullrequestsApi = container.resolve(ServiceTokens.PullrequestsApi);
26809
+ return new DefaultReviewerService(pullrequestsApi);
26810
+ });
26811
+ container.register(ServiceTokens.ListDefaultReviewersCommand, () => {
26812
+ const service = container.resolve(ServiceTokens.DefaultReviewerService);
26813
+ const contextService = container.resolve(ServiceTokens.ContextService);
26814
+ const output = container.resolve(ServiceTokens.OutputService);
26815
+ return new ListDefaultReviewersCommand(service, contextService, output);
26816
+ });
26817
+ container.register(ServiceTokens.AddDefaultReviewerCommand, () => {
26818
+ const service = container.resolve(ServiceTokens.DefaultReviewerService);
26819
+ const usersApi = container.resolve(ServiceTokens.UsersApi);
26820
+ const contextService = container.resolve(ServiceTokens.ContextService);
26821
+ const output = container.resolve(ServiceTokens.OutputService);
26822
+ return new AddDefaultReviewerCommand(service, usersApi, contextService, output);
26823
+ });
26824
+ container.register(ServiceTokens.RemoveDefaultReviewerCommand, () => {
26825
+ const service = container.resolve(ServiceTokens.DefaultReviewerService);
26826
+ const usersApi = container.resolve(ServiceTokens.UsersApi);
26827
+ const contextService = container.resolve(ServiceTokens.ContextService);
26828
+ const output = container.resolve(ServiceTokens.OutputService);
26829
+ return new RemoveDefaultReviewerCommand(service, usersApi, contextService, output);
26830
+ });
26446
26831
  container.register(ServiceTokens.CreatePRCommand, () => {
26447
26832
  const pullrequestsApi = container.resolve(ServiceTokens.PullrequestsApi);
26833
+ const usersApi = container.resolve(ServiceTokens.UsersApi);
26448
26834
  const contextService = container.resolve(ServiceTokens.ContextService);
26449
26835
  const gitService = container.resolve(ServiceTokens.GitService);
26836
+ const defaultReviewerService = container.resolve(ServiceTokens.DefaultReviewerService);
26837
+ const configService = container.resolve(ServiceTokens.ConfigService);
26450
26838
  const output = container.resolve(ServiceTokens.OutputService);
26451
- return new CreatePRCommand(pullrequestsApi, contextService, gitService, output);
26839
+ return new CreatePRCommand(pullrequestsApi, usersApi, contextService, gitService, defaultReviewerService, configService, output);
26452
26840
  });
26453
26841
  container.register(ServiceTokens.ListPRsCommand, () => {
26454
26842
  const pullrequestsApi = container.resolve(ServiceTokens.PullrequestsApi);
@@ -26730,7 +27118,9 @@ if (process.argv.includes("--get-yargs-completions") || process.env.COMP_LINE) {
26730
27118
  if (env2.prev === "auth") {
26731
27119
  completions.push("login", "logout", "status", "token");
26732
27120
  } else if (env2.prev === "repo") {
26733
- completions.push("clone", "create", "list", "view", "delete");
27121
+ completions.push("clone", "create", "list", "view", "delete", "default-reviewers");
27122
+ } else if (env2.prev === "default-reviewers") {
27123
+ completions.push("list", "add", "remove");
26734
27124
  } else if (env2.prev === "pr") {
26735
27125
  completions.push("create", "list", "view", "activity", "checks", "edit", "merge", "approve", "decline", "ready", "checkout", "diff", "comments", "reviewers");
26736
27126
  } else if (env2.prev === "reviewers") {
@@ -26904,18 +27294,50 @@ repoCmd.command("delete <repository>").description("Delete a repository").option
26904
27294
  const context = createContext(cli);
26905
27295
  await runCommand(ServiceTokens.DeleteRepoCommand, withGlobalOptions({ repository, ...options }, context), cli, context);
26906
27296
  });
27297
+ var repoDefaultReviewersCmd = new Command("default-reviewers").description("Manage default reviewers for a repository");
27298
+ repoDefaultReviewersCmd.command("list").description("List default reviewers for a repository").option("--repo-only", "Only show reviewers configured on the repository (exclude project-inherited)").addHelpText("after", buildHelpText({
27299
+ examples: [
27300
+ "bb repo default-reviewers list",
27301
+ "bb repo default-reviewers list --repo-only",
27302
+ "bb repo default-reviewers list --json"
27303
+ ]
27304
+ })).action(async (options) => {
27305
+ const context = createContext(cli);
27306
+ await runCommand(ServiceTokens.ListDefaultReviewersCommand, withGlobalOptions(options, context), cli, context);
27307
+ });
27308
+ repoDefaultReviewersCmd.command("add <user>").description("Add a default reviewer to a repository (accepts account ID or {uuid})").addHelpText("after", buildHelpText({
27309
+ examples: [
27310
+ 'bb repo default-reviewers add "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f"',
27311
+ 'bb repo default-reviewers add "{c1cb1bb5-2e32-456e-a373-43978dc12aa1}"'
27312
+ ]
27313
+ })).action(async (username, options) => {
27314
+ const context = createContext(cli);
27315
+ await runCommand(ServiceTokens.AddDefaultReviewerCommand, withGlobalOptions({ username, ...options }, context), cli, context);
27316
+ });
27317
+ repoDefaultReviewersCmd.command("remove <user>").description("Remove a default reviewer from a repository (accepts account ID or {uuid})").option("-y, --yes", "Skip confirmation prompt").addHelpText("after", buildHelpText({
27318
+ examples: [
27319
+ 'bb repo default-reviewers remove "712020:3cfed7e0-0ed6-49fc-bb35-410a00ccee6f" --yes'
27320
+ ]
27321
+ })).action(async (username, options) => {
27322
+ const context = createContext(cli);
27323
+ await runCommand(ServiceTokens.RemoveDefaultReviewerCommand, withGlobalOptions({ username, ...options }, context), cli, context);
27324
+ });
27325
+ repoCmd.addCommand(repoDefaultReviewersCmd);
26907
27326
  cli.addCommand(repoCmd);
26908
27327
  var prCmd = new Command("pr").description("Manage pull requests");
26909
- prCmd.command("create").description("Create a pull request").option("-t, --title <title>", "Pull request title").option("-b, --body <body>", "Pull request description").option("-s, --source <branch>", "Source branch (default: current branch)").option("-d, --destination <branch>", "Destination branch (default: main)").option("--close-source-branch", "Close source branch after merge").option("--draft", "Create the pull request as draft").addHelpText("after", buildHelpText({
27328
+ prCmd.command("create").description("Create a pull request").option("-t, --title <title>", "Pull request title").option("-b, --body <body>", "Pull request description").option("-s, --source <branch>", "Source branch (default: current branch)").option("-d, --destination <branch>", "Destination branch (default: main)").option("--close-source-branch", "Close source branch after merge").option("--draft", "Create the pull request as draft").option("--reviewer <user>", "Add a reviewer by account ID or {uuid} (repeatable)", (value, previous) => previous.concat([value]), []).option("--default-reviewers", "Include the repository's default reviewers").option("--no-default-reviewers", "Skip the repository's default reviewers even when prCreateIncludeDefaultReviewers is true").addHelpText("after", buildHelpText({
26910
27329
  examples: [
26911
27330
  'bb pr create -t "My PR" -b "Description"',
26912
27331
  'bb pr create -t "My PR" --draft',
26913
27332
  'bb pr create -t "My PR" -s feature -d develop',
26914
- 'bb pr create -t "My PR" --close-source-branch'
27333
+ 'bb pr create -t "My PR" --close-source-branch',
27334
+ 'bb pr create -t "My PR" --default-reviewers',
27335
+ 'bb pr create -t "My PR" --reviewer jdoe --reviewer asmith'
26915
27336
  ],
26916
27337
  defaults: {
26917
27338
  source: "current git branch",
26918
- destination: "main"
27339
+ destination: "main",
27340
+ "default-reviewers": "false (override with --default-reviewers or config key prCreateIncludeDefaultReviewers)"
26919
27341
  }
26920
27342
  })).action(async (options) => {
26921
27343
  const context = createContext(cli);
@@ -26964,7 +27386,7 @@ prCmd.command("activity <id>").description("Show pull request activity log").opt
26964
27386
  const context = createContext(cli);
26965
27387
  await runCommand(ServiceTokens.ActivityPRCommand, withGlobalOptions({ id, ...options }, context), cli, context);
26966
27388
  });
26967
- prCmd.command("checks <id>").description("Show CI/CD checks and build status for a pull request").option("--json", "Output as JSON").addHelpText("after", buildHelpText({
27389
+ prCmd.command("checks <id>").description("Show CI/CD checks and build status for a pull request").addHelpText("after", buildHelpText({
26968
27390
  examples: ["bb pr checks 42", "bb pr checks 42 --json"]
26969
27391
  })).action(async (id, options) => {
26970
27392
  const context = createContext(cli);
@@ -27060,11 +27482,11 @@ prCommentsCmd.command("edit <pr-id> <comment-id> <message>").description("Edit a
27060
27482
  const context = createContext(cli);
27061
27483
  await runCommand(ServiceTokens.EditCommentPRCommand, withGlobalOptions({ prId, commentId, message }, context), cli, context);
27062
27484
  });
27063
- prCommentsCmd.command("delete <pr-id> <comment-id>").description("Delete a comment on a pull request").addHelpText("after", buildHelpText({
27064
- examples: ["bb pr comments delete 42 12345"]
27485
+ prCommentsCmd.command("delete <pr-id> <comment-id>").description("Delete a comment on a pull request").option("-y, --yes", "Skip confirmation prompt").addHelpText("after", buildHelpText({
27486
+ examples: ["bb pr comments delete 42 12345 --yes"]
27065
27487
  })).action(async (prId, commentId, options) => {
27066
27488
  const context = createContext(cli);
27067
- await runCommand(ServiceTokens.DeleteCommentPRCommand, withGlobalOptions({ prId, commentId }, context), cli, context);
27489
+ await runCommand(ServiceTokens.DeleteCommentPRCommand, withGlobalOptions({ prId, commentId, ...options }, context), cli, context);
27068
27490
  });
27069
27491
  var prReviewersCmd = new Command("reviewers").description("Manage pull request reviewers");
27070
27492
  prReviewersCmd.command("list <id>").description("List reviewers on a pull request").addHelpText("after", buildHelpText({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilatos/bitbucket-cli",
3
- "version": "1.12.0",
3
+ "version": "1.13.0",
4
4
  "description": "A command-line interface for Bitbucket Cloud",
5
5
  "author": "",
6
6
  "license": "MIT",