@pilatos/bitbucket-cli 1.8.0 → 1.8.1

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 +322 -81
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -44211,7 +44211,7 @@ var ServiceTokens = {
44211
44211
  };
44212
44212
 
44213
44213
  // src/services/config.service.ts
44214
- import { join } from "path";
44214
+ import { join, win32 } from "path";
44215
44215
  import { homedir } from "os";
44216
44216
 
44217
44217
  // src/types/errors.ts
@@ -44282,9 +44282,24 @@ class ConfigService {
44282
44282
  configDir;
44283
44283
  configFile;
44284
44284
  configCache = null;
44285
- constructor(configDir) {
44286
- this.configDir = configDir ?? join(homedir(), ".config", "bb");
44287
- this.configFile = join(this.configDir, "config.json");
44285
+ constructor(configDir, options = {}) {
44286
+ const platform = options.platform ?? process.platform;
44287
+ const joinPath = platform === "win32" ? win32.join : join;
44288
+ this.configDir = configDir ?? this.resolveDefaultConfigDir({ ...options, platform });
44289
+ this.configFile = joinPath(this.configDir, "config.json");
44290
+ }
44291
+ resolveDefaultConfigDir(options) {
44292
+ const platform = options.platform ?? process.platform;
44293
+ if (platform === "win32") {
44294
+ const appDataDir = options.appData ?? process.env.APPDATA;
44295
+ if (appDataDir) {
44296
+ return win32.join(appDataDir, "bb");
44297
+ }
44298
+ const homeDir2 = options.homeDir ?? homedir();
44299
+ return win32.join(homeDir2, "AppData", "Roaming", "bb");
44300
+ }
44301
+ const homeDir = options.homeDir ?? homedir();
44302
+ return join(homeDir, ".config", "bb");
44288
44303
  }
44289
44304
  async ensureConfigDir() {
44290
44305
  try {
@@ -44354,6 +44369,11 @@ class ConfigService {
44354
44369
  apiToken: credentials.apiToken
44355
44370
  });
44356
44371
  }
44372
+ async clearCredentials() {
44373
+ const config = await this.getConfig();
44374
+ const { username: _username, apiToken: _apiToken, ...rest } = config;
44375
+ await this.setConfig(rest);
44376
+ }
44357
44377
  async clearConfig() {
44358
44378
  this.configCache = null;
44359
44379
  await this.setConfig({});
@@ -45018,6 +45038,9 @@ class OutputService {
45018
45038
  json(data) {
45019
45039
  console.log(JSON.stringify(data, null, 2));
45020
45040
  }
45041
+ jsonError(data) {
45042
+ console.error(JSON.stringify(data));
45043
+ }
45021
45044
  table(headers, rows) {
45022
45045
  if (rows.length === 0) {
45023
45046
  return;
@@ -45149,14 +45172,22 @@ function parseSettableConfigValue(key, value) {
45149
45172
  case "skipVersionCheck": {
45150
45173
  const parsed = parseBooleanLiteral(value);
45151
45174
  if (parsed === undefined) {
45152
- throw new Error("Invalid value for 'skipVersionCheck'. Expected 'true' or 'false'.");
45175
+ throw new BBError({
45176
+ code: 5002 /* VALIDATION_INVALID */,
45177
+ message: "Invalid value for 'skipVersionCheck'. Expected 'true' or 'false'.",
45178
+ context: { key, value }
45179
+ });
45153
45180
  }
45154
45181
  return parsed;
45155
45182
  }
45156
45183
  case "versionCheckInterval": {
45157
45184
  const parsed = parsePositiveIntegerLiteral(value);
45158
45185
  if (parsed === undefined) {
45159
- throw new Error("Invalid value for 'versionCheckInterval'. Expected a positive integer (1 or greater).");
45186
+ throw new BBError({
45187
+ code: 5002 /* VALIDATION_INVALID */,
45188
+ message: "Invalid value for 'versionCheckInterval'. Expected a positive integer (1 or greater).",
45189
+ context: { key, value }
45190
+ });
45160
45191
  }
45161
45192
  return parsed;
45162
45193
  }
@@ -51614,7 +51645,9 @@ class BaseCommand {
51614
51645
  }
51615
51646
  }
51616
51647
  handleError(error, context) {
51617
- if (error instanceof Error) {
51648
+ if (context.globalOptions.json) {
51649
+ this.output.jsonError(this.normalizeErrorForJson(error));
51650
+ } else if (error instanceof Error) {
51618
51651
  this.output.error(error.message);
51619
51652
  } else {
51620
51653
  this.output.error(String(error));
@@ -51623,6 +51656,23 @@ class BaseCommand {
51623
51656
  process.exitCode = 1;
51624
51657
  }
51625
51658
  }
51659
+ normalizeErrorForJson(error) {
51660
+ if (error instanceof BBError) {
51661
+ return error.toJSON();
51662
+ }
51663
+ if (error instanceof Error) {
51664
+ return {
51665
+ name: error.name,
51666
+ code: 9999 /* UNKNOWN */,
51667
+ message: error.message
51668
+ };
51669
+ }
51670
+ return {
51671
+ name: "Error",
51672
+ code: 9999 /* UNKNOWN */,
51673
+ message: String(error)
51674
+ };
51675
+ }
51626
51676
  requireOption(value, name, message) {
51627
51677
  if (value === undefined || value === null || value === "") {
51628
51678
  throw new BBError({
@@ -51649,10 +51699,16 @@ class LoginCommand extends BaseCommand {
51649
51699
  const username = options.username || process.env.BB_USERNAME;
51650
51700
  const apiToken = options.password || process.env.BB_API_TOKEN;
51651
51701
  if (!username) {
51652
- throw new Error("Username is required. Use --username option or set BB_USERNAME environment variable.");
51702
+ throw new BBError({
51703
+ code: 5001 /* VALIDATION_REQUIRED */,
51704
+ message: "Username is required. Use --username option or set BB_USERNAME environment variable."
51705
+ });
51653
51706
  }
51654
51707
  if (!apiToken) {
51655
- throw new Error("API token is required. Use --password option or set BB_API_TOKEN environment variable.");
51708
+ throw new BBError({
51709
+ code: 5001 /* VALIDATION_REQUIRED */,
51710
+ message: "API token is required. Use --password option or set BB_API_TOKEN environment variable."
51711
+ });
51656
51712
  }
51657
51713
  await this.configService.setCredentials({ username, apiToken });
51658
51714
  try {
@@ -51671,8 +51727,11 @@ class LoginCommand extends BaseCommand {
51671
51727
  }
51672
51728
  this.output.success(`Logged in as ${user.display_name} (${user.username})`);
51673
51729
  } catch (error) {
51674
- await this.configService.clearConfig();
51675
- throw new Error(`Authentication failed: ${error instanceof Error ? error.message : String(error)}`);
51730
+ await this.configService.clearCredentials();
51731
+ throw new BBError({
51732
+ code: 1002 /* AUTH_INVALID */,
51733
+ message: `Authentication failed: ${error instanceof Error ? error.message : String(error)}`
51734
+ });
51676
51735
  }
51677
51736
  }
51678
51737
  }
@@ -51687,7 +51746,7 @@ class LogoutCommand extends BaseCommand {
51687
51746
  this.configService = configService;
51688
51747
  }
51689
51748
  async execute(_options, context) {
51690
- await this.configService.clearConfig();
51749
+ await this.configService.clearCredentials();
51691
51750
  if (context.globalOptions.json) {
51692
51751
  this.output.json({ authenticated: false, success: true });
51693
51752
  return;
@@ -51741,7 +51800,11 @@ class StatusCommand extends BaseCommand {
51741
51800
  this.output.text(` Default workspace: ${this.output.highlight(config.defaultWorkspace)}`);
51742
51801
  }
51743
51802
  } catch (error) {
51744
- throw new Error(`Authentication is invalid or expired. Run ${this.output.highlight("bb auth login")} to re-authenticate.`);
51803
+ throw new BBError({
51804
+ code: 1002 /* AUTH_INVALID */,
51805
+ message: `Authentication is invalid or expired. Run ${this.output.highlight("bb auth login")} to re-authenticate.`,
51806
+ cause: error instanceof Error ? error : undefined
51807
+ });
51745
51808
  }
51746
51809
  }
51747
51810
  }
@@ -51758,7 +51821,10 @@ class TokenCommand extends BaseCommand {
51758
51821
  async execute(_options, context) {
51759
51822
  const credentials = await this.configService.getCredentials();
51760
51823
  if (!credentials.username || !credentials.apiToken) {
51761
- throw new Error("Not authenticated. Run 'bb auth login' first.");
51824
+ throw new BBError({
51825
+ code: 1001 /* AUTH_REQUIRED */,
51826
+ message: "Not authenticated. Run 'bb auth login' first."
51827
+ });
51762
51828
  }
51763
51829
  const token = Buffer.from(`${credentials.username}:${credentials.apiToken}`).toString("base64");
51764
51830
  if (context.globalOptions.json) {
@@ -51806,7 +51872,10 @@ class CloneCommand extends BaseCommand {
51806
51872
  if (parts.length === 1) {
51807
51873
  const config = await this.configService.getConfig();
51808
51874
  if (!config.defaultWorkspace) {
51809
- throw new Error("No workspace specified. Use workspace/repo format or set a default workspace.");
51875
+ throw new BBError({
51876
+ code: 6002 /* CONTEXT_WORKSPACE_NOT_FOUND */,
51877
+ message: "No workspace specified. Use workspace/repo format or set a default workspace."
51878
+ });
51810
51879
  }
51811
51880
  workspace = config.defaultWorkspace;
51812
51881
  repoSlug = parts[0];
@@ -51814,7 +51883,11 @@ class CloneCommand extends BaseCommand {
51814
51883
  workspace = parts[0];
51815
51884
  repoSlug = parts[1];
51816
51885
  } else {
51817
- throw new Error("Invalid repository format. Use workspace/repo or a full URL.");
51886
+ throw new BBError({
51887
+ code: 5002 /* VALIDATION_INVALID */,
51888
+ message: "Invalid repository format. Use workspace/repo or a full URL.",
51889
+ context: { repository }
51890
+ });
51818
51891
  }
51819
51892
  return `git@bitbucket.org:${workspace}/${repoSlug}.git`;
51820
51893
  }
@@ -51822,7 +51895,11 @@ class CloneCommand extends BaseCommand {
51822
51895
  const parts = repository.split("/");
51823
51896
  const lastPart = parts.at(-1);
51824
51897
  if (!lastPart) {
51825
- throw new Error("Invalid repository format.");
51898
+ throw new BBError({
51899
+ code: 5002 /* VALIDATION_INVALID */,
51900
+ message: "Invalid repository format.",
51901
+ context: { repository }
51902
+ });
51826
51903
  }
51827
51904
  return lastPart.replace(".git", "");
51828
51905
  }
@@ -51878,12 +51955,61 @@ class CreateRepoCommand extends BaseCommand {
51878
51955
  }
51879
51956
  const config = await this.configService.getConfig();
51880
51957
  if (!config.defaultWorkspace) {
51881
- throw new Error("No workspace specified. Use --workspace option or set a default workspace.");
51958
+ throw new BBError({
51959
+ code: 6002 /* CONTEXT_WORKSPACE_NOT_FOUND */,
51960
+ message: "No workspace specified. Use --workspace option or set a default workspace."
51961
+ });
51882
51962
  }
51883
51963
  return config.defaultWorkspace;
51884
51964
  }
51885
51965
  }
51886
51966
 
51967
+ // src/services/pagination.ts
51968
+ var DEFAULT_LIMIT = 25;
51969
+ var MAX_PAGE_LENGTH = 50;
51970
+ function parseLimit(limit, fallback = DEFAULT_LIMIT) {
51971
+ if (!limit) {
51972
+ return fallback;
51973
+ }
51974
+ const parsed = Number.parseInt(limit, 10);
51975
+ if (Number.isNaN(parsed) || parsed <= 0) {
51976
+ return fallback;
51977
+ }
51978
+ return parsed;
51979
+ }
51980
+ async function collectPages(options) {
51981
+ const { fetchPage, shouldInclude } = options;
51982
+ const limit = Math.max(0, options.limit);
51983
+ if (limit === 0) {
51984
+ return [];
51985
+ }
51986
+ const requestedPageSize = options.pageSize ?? limit;
51987
+ const pagelen = Math.max(1, Math.min(requestedPageSize, MAX_PAGE_LENGTH));
51988
+ const items = [];
51989
+ let page = 1;
51990
+ while (items.length < limit) {
51991
+ const data = await fetchPage(page, pagelen);
51992
+ const pageValues = data.values ? Array.from(data.values) : [];
51993
+ if (pageValues.length === 0) {
51994
+ break;
51995
+ }
51996
+ for (const value of pageValues) {
51997
+ if (shouldInclude && !shouldInclude(value)) {
51998
+ continue;
51999
+ }
52000
+ items.push(value);
52001
+ if (items.length >= limit) {
52002
+ return items;
52003
+ }
52004
+ }
52005
+ if (!data.next) {
52006
+ break;
52007
+ }
52008
+ page += 1;
52009
+ }
52010
+ return items;
52011
+ }
52012
+
51887
52013
  // src/commands/repo/list.command.ts
51888
52014
  class ListReposCommand extends BaseCommand {
51889
52015
  repositoriesApi;
@@ -51897,11 +52023,18 @@ class ListReposCommand extends BaseCommand {
51897
52023
  }
51898
52024
  async execute(options, context) {
51899
52025
  const workspace = await this.resolveWorkspace(options.workspace ?? context.globalOptions.workspace);
51900
- const limit = Number.parseInt(options.limit || "25", 10);
51901
- const response = await this.repositoriesApi.repositoriesWorkspaceGet({
51902
- workspace
52026
+ const limit = parseLimit(options.limit);
52027
+ const repos = await collectPages({
52028
+ limit,
52029
+ fetchPage: async (page, pagelen) => {
52030
+ const response = await this.repositoriesApi.repositoriesWorkspaceGet({
52031
+ workspace
52032
+ }, {
52033
+ params: { page, pagelen }
52034
+ });
52035
+ return response.data;
52036
+ }
51903
52037
  });
51904
- const repos = Array.from(response.data.values ?? []).slice(0, limit);
51905
52038
  if (context.globalOptions.json) {
51906
52039
  this.output.json({
51907
52040
  workspace,
@@ -51927,7 +52060,10 @@ class ListReposCommand extends BaseCommand {
51927
52060
  }
51928
52061
  const config = await this.configService.getConfig();
51929
52062
  if (!config.defaultWorkspace) {
51930
- throw new Error("No workspace specified. Use --workspace option or set a default workspace.");
52063
+ throw new BBError({
52064
+ code: 6002 /* CONTEXT_WORKSPACE_NOT_FOUND */,
52065
+ message: "No workspace specified. Use --workspace option or set a default workspace."
52066
+ });
51931
52067
  }
51932
52068
  return config.defaultWorkspace;
51933
52069
  }
@@ -52012,8 +52148,11 @@ class DeleteRepoCommand extends BaseCommand {
52012
52148
  }
52013
52149
  const repoContext = await this.contextService.requireRepoContext(contextOptions);
52014
52150
  if (!yes) {
52015
- throw new Error(`This will permanently delete ${repoContext.workspace}/${repoContext.repoSlug}.
52016
- ` + "Use --yes to confirm deletion.");
52151
+ throw new BBError({
52152
+ code: 5001 /* VALIDATION_REQUIRED */,
52153
+ message: `This will permanently delete ${repoContext.workspace}/${repoContext.repoSlug}.
52154
+ ` + "Use --yes to confirm deletion."
52155
+ });
52017
52156
  }
52018
52157
  await this.repositoriesApi.repositoriesWorkspaceRepoSlugDelete({
52019
52158
  workspace: repoContext.workspace,
@@ -52046,7 +52185,10 @@ class CreatePRCommand extends BaseCommand {
52046
52185
  }
52047
52186
  async execute(options, context) {
52048
52187
  if (!options.title) {
52049
- throw new Error("Pull request title is required. Use --title option.");
52188
+ throw new BBError({
52189
+ code: 5001 /* VALIDATION_REQUIRED */,
52190
+ message: "Pull request title is required. Use --title option."
52191
+ });
52050
52192
  }
52051
52193
  const repoContext = await this.contextService.requireRepoContext({
52052
52194
  ...context.globalOptions,
@@ -52110,13 +52252,20 @@ class ListPRsCommand extends BaseCommand {
52110
52252
  ...options
52111
52253
  });
52112
52254
  const state = options.state || "OPEN";
52113
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsGet({
52114
- workspace: repoContext.workspace,
52115
- repoSlug: repoContext.repoSlug,
52116
- state
52255
+ const limit = parseLimit(options.limit);
52256
+ const values = await collectPages({
52257
+ limit,
52258
+ fetchPage: async (page, pagelen) => {
52259
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsGet({
52260
+ workspace: repoContext.workspace,
52261
+ repoSlug: repoContext.repoSlug,
52262
+ state
52263
+ }, {
52264
+ params: { page, pagelen }
52265
+ });
52266
+ return response.data;
52267
+ }
52117
52268
  });
52118
- const data = response.data;
52119
- const values = data.values ? Array.from(data.values) : [];
52120
52269
  if (context.globalOptions.json) {
52121
52270
  this.output.json({
52122
52271
  workspace: repoContext.workspace,
@@ -52299,18 +52448,31 @@ class EditPRCommand extends BaseCommand {
52299
52448
  prId = Number.parseInt(options.id, 10);
52300
52449
  } else {
52301
52450
  const currentBranch = await this.gitService.getCurrentBranch();
52302
- const prsResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsGet({
52303
- workspace: repoContext.workspace,
52304
- repoSlug: repoContext.repoSlug,
52305
- state: "OPEN"
52306
- });
52307
- const values = prsResponse.data.values ? Array.from(prsResponse.data.values) : [];
52308
- const matchingPR = values.find((pr2) => {
52309
- const source = pr2.source;
52310
- return source?.branch?.name === currentBranch;
52451
+ const matches = await collectPages({
52452
+ limit: 1,
52453
+ pageSize: MAX_PAGE_LENGTH,
52454
+ fetchPage: async (page, pagelen) => {
52455
+ const response2 = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsGet({
52456
+ workspace: repoContext.workspace,
52457
+ repoSlug: repoContext.repoSlug,
52458
+ state: "OPEN"
52459
+ }, {
52460
+ params: { page, pagelen }
52461
+ });
52462
+ return response2.data;
52463
+ },
52464
+ shouldInclude: (pullRequest) => {
52465
+ const source = pullRequest.source;
52466
+ return source?.branch?.name === currentBranch;
52467
+ }
52311
52468
  });
52469
+ const matchingPR = matches[0];
52312
52470
  if (!matchingPR) {
52313
- throw new Error(`No open pull request found for current branch '${currentBranch}'. Specify a PR ID explicitly.`);
52471
+ throw new BBError({
52472
+ code: 2002 /* API_NOT_FOUND */,
52473
+ message: `No open pull request found for current branch '${currentBranch}'. Specify a PR ID explicitly.`,
52474
+ context: { branch: currentBranch }
52475
+ });
52314
52476
  }
52315
52477
  prId = matchingPR.id;
52316
52478
  }
@@ -52319,11 +52481,19 @@ class EditPRCommand extends BaseCommand {
52319
52481
  try {
52320
52482
  body = fs.readFileSync(options.bodyFile, "utf-8");
52321
52483
  } catch (err) {
52322
- throw new Error(`Failed to read file '${options.bodyFile}': ${err instanceof Error ? err.message : "Unknown error"}`);
52484
+ throw new BBError({
52485
+ code: 9999 /* UNKNOWN */,
52486
+ message: `Failed to read file '${options.bodyFile}': ${err instanceof Error ? err.message : "Unknown error"}`,
52487
+ cause: err instanceof Error ? err : undefined,
52488
+ context: { bodyFile: options.bodyFile }
52489
+ });
52323
52490
  }
52324
52491
  }
52325
52492
  if (!options.title && !body) {
52326
- throw new Error("At least one of --title or --body (or --body-file) is required.");
52493
+ throw new BBError({
52494
+ code: 5001 /* VALIDATION_REQUIRED */,
52495
+ message: "At least one of --title or --body (or --body-file) is required."
52496
+ });
52327
52497
  }
52328
52498
  const request = {
52329
52499
  type: "pullrequest"
@@ -52540,7 +52710,11 @@ class CheckoutPRCommand extends BaseCommand {
52540
52710
  const branchName = pr.source?.branch?.name;
52541
52711
  const localBranchName = `pr-${prId}`;
52542
52712
  if (!branchName) {
52543
- throw new Error("Pull request source branch not found");
52713
+ throw new BBError({
52714
+ code: 2002 /* API_NOT_FOUND */,
52715
+ message: "Pull request source branch not found",
52716
+ context: { pullRequestId: prId }
52717
+ });
52544
52718
  }
52545
52719
  await this.gitService.fetch();
52546
52720
  let checkedOutBranch;
@@ -52601,18 +52775,39 @@ class DiffPRCommand extends BaseCommand {
52601
52775
  if (options.id) {
52602
52776
  prId = Number.parseInt(options.id, 10);
52603
52777
  if (Number.isNaN(prId)) {
52604
- throw new TypeError("Invalid PR ID");
52778
+ throw new BBError({
52779
+ code: 5002 /* VALIDATION_INVALID */,
52780
+ message: "Invalid PR ID",
52781
+ context: { id: options.id }
52782
+ });
52605
52783
  }
52606
52784
  } else {
52607
52785
  const currentBranch = await this.gitService.getCurrentBranch();
52608
- const prsResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsGet({
52609
- workspace: repoContext.workspace,
52610
- repoSlug: repoContext.repoSlug,
52611
- state: "OPEN"
52786
+ const matches = await collectPages({
52787
+ limit: 1,
52788
+ pageSize: MAX_PAGE_LENGTH,
52789
+ fetchPage: async (page, pagelen) => {
52790
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsGet({
52791
+ workspace: repoContext.workspace,
52792
+ repoSlug: repoContext.repoSlug,
52793
+ state: "OPEN"
52794
+ }, {
52795
+ params: { page, pagelen }
52796
+ });
52797
+ return response.data;
52798
+ },
52799
+ shouldInclude: (pullRequest) => {
52800
+ const source = pullRequest.source;
52801
+ return source?.branch?.name === currentBranch;
52802
+ }
52612
52803
  });
52613
- const pr = Array.from(prsResponse.data.values ?? []).find((p) => p.source?.branch?.name === currentBranch);
52804
+ const pr = matches[0];
52614
52805
  if (!pr) {
52615
- throw new Error(`No open pull request found for branch "${currentBranch}"`);
52806
+ throw new BBError({
52807
+ code: 2002 /* API_NOT_FOUND */,
52808
+ message: `No open pull request found for branch "${currentBranch}"`,
52809
+ context: { branch: currentBranch }
52810
+ });
52616
52811
  }
52617
52812
  prId = pr.id;
52618
52813
  }
@@ -52687,11 +52882,13 @@ class DiffPRCommand extends BaseCommand {
52687
52882
  repoSlug,
52688
52883
  pullRequestId: prId
52689
52884
  });
52690
- const diffUrl = prResponse.data.links?.diff?.href;
52691
- if (!diffUrl) {
52692
- throw new Error("Could not get diff URL");
52885
+ const links = prResponse.data.links;
52886
+ const htmlUrl = links?.html?.href;
52887
+ if (htmlUrl) {
52888
+ const normalizedHtmlUrl = htmlUrl.replace(/\/$/, "");
52889
+ return `${normalizedHtmlUrl}/diff`;
52693
52890
  }
52694
- return diffUrl.replace(/api\.bitbucket\.org\/2\.0\/repositories\/(.*?)\/pullrequests\/(\d+)\/diff/, "bitbucket.org/$1/pull-requests/$2/diff");
52891
+ return `https://bitbucket.org/${workspace}/${repoSlug}/pull-requests/${prId}/diff`;
52695
52892
  }
52696
52893
  async showStat(workspace, repoSlug, prId, useJson) {
52697
52894
  const diffstatResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdDiffstatGet({
@@ -52814,15 +53011,28 @@ class ActivityPRCommand extends BaseCommand {
52814
53011
  ...options
52815
53012
  });
52816
53013
  const prId = Number.parseInt(options.id, 10);
52817
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdActivityGet({
52818
- workspace: repoContext.workspace,
52819
- repoSlug: repoContext.repoSlug,
52820
- pullRequestId: prId
52821
- });
52822
- const data = response.data;
52823
- const values = data?.values ? Array.from(data.values) : [];
52824
53014
  const filterTypes = this.parseTypeFilter(options.type);
52825
- const activities = filterTypes.length > 0 ? values.filter((activity) => filterTypes.includes(this.getActivityType(activity))) : values;
53015
+ const limit = parseLimit(options.limit);
53016
+ const activities = await collectPages({
53017
+ limit,
53018
+ fetchPage: async (page, pagelen) => {
53019
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdActivityGet({
53020
+ workspace: repoContext.workspace,
53021
+ repoSlug: repoContext.repoSlug,
53022
+ pullRequestId: prId
53023
+ }, {
53024
+ params: { page, pagelen }
53025
+ });
53026
+ return response.data;
53027
+ },
53028
+ shouldInclude: (activity) => {
53029
+ if (filterTypes.length === 0) {
53030
+ return true;
53031
+ }
53032
+ return filterTypes.includes(this.getActivityType(activity));
53033
+ }
53034
+ });
53035
+ const typedActivities = activities;
52826
53036
  if (context.globalOptions.json) {
52827
53037
  this.output.json({
52828
53038
  workspace: repoContext.workspace,
@@ -52831,12 +53041,12 @@ class ActivityPRCommand extends BaseCommand {
52831
53041
  filters: {
52832
53042
  types: filterTypes
52833
53043
  },
52834
- count: activities.length,
52835
- activities
53044
+ count: typedActivities.length,
53045
+ activities: typedActivities
52836
53046
  });
52837
53047
  return;
52838
53048
  }
52839
- if (activities.length === 0) {
53049
+ if (typedActivities.length === 0) {
52840
53050
  if (filterTypes.length > 0) {
52841
53051
  this.output.info("No activity entries matched the requested filter");
52842
53052
  } else {
@@ -52844,7 +53054,7 @@ class ActivityPRCommand extends BaseCommand {
52844
53054
  }
52845
53055
  return;
52846
53056
  }
52847
- const rows = activities.map((activity) => {
53057
+ const rows = typedActivities.map((activity) => {
52848
53058
  const activityType = this.getActivityType(activity);
52849
53059
  return [
52850
53060
  activityType.toUpperCase(),
@@ -53055,13 +53265,20 @@ class ListCommentsPRCommand extends BaseCommand {
53055
53265
  ...options
53056
53266
  });
53057
53267
  const prId = Number.parseInt(options.id, 10);
53058
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdCommentsGet({
53059
- workspace: repoContext.workspace,
53060
- repoSlug: repoContext.repoSlug,
53061
- pullRequestId: prId
53268
+ const limit = parseLimit(options.limit);
53269
+ const values = await collectPages({
53270
+ limit,
53271
+ fetchPage: async (page, pagelen) => {
53272
+ const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdCommentsGet({
53273
+ workspace: repoContext.workspace,
53274
+ repoSlug: repoContext.repoSlug,
53275
+ pullRequestId: prId
53276
+ }, {
53277
+ params: { page, pagelen }
53278
+ });
53279
+ return response.data;
53280
+ }
53062
53281
  });
53063
- const data = response.data;
53064
- const values = data.values ? Array.from(data.values) : [];
53065
53282
  if (context.globalOptions.json) {
53066
53283
  this.output.json({
53067
53284
  pullRequestId: prId,
@@ -53463,10 +53680,18 @@ class GetConfigCommand extends BaseCommand {
53463
53680
  async execute(options, context) {
53464
53681
  const { key } = options;
53465
53682
  if (GetConfigCommand.HIDDEN_KEYS.includes(key)) {
53466
- throw new Error(`Cannot display '${key}' - use 'bb auth token' to get authentication credentials`);
53683
+ throw new BBError({
53684
+ code: 4003 /* CONFIG_INVALID_KEY */,
53685
+ message: `Cannot display '${key}' - use 'bb auth token' to get authentication credentials`,
53686
+ context: { key }
53687
+ });
53467
53688
  }
53468
53689
  if (!isReadableConfigKey(key)) {
53469
- throw new Error(`Unknown config key '${key}'. Valid keys: ${READABLE_CONFIG_KEYS.join(", ")}`);
53690
+ throw new BBError({
53691
+ code: 4003 /* CONFIG_INVALID_KEY */,
53692
+ message: `Unknown config key '${key}'. Valid keys: ${READABLE_CONFIG_KEYS.join(", ")}`,
53693
+ context: { key }
53694
+ });
53470
53695
  }
53471
53696
  const rawValue = await this.configService.getValue(key);
53472
53697
  const value = normalizeReadableConfigValue(key, rawValue);
@@ -53494,10 +53719,18 @@ class SetConfigCommand extends BaseCommand {
53494
53719
  async execute(options, context) {
53495
53720
  const { key, value } = options;
53496
53721
  if (SetConfigCommand.PROTECTED_KEYS.includes(key)) {
53497
- throw new Error(`Cannot set '${key}' directly. Use 'bb auth login' to configure authentication.`);
53722
+ throw new BBError({
53723
+ code: 4003 /* CONFIG_INVALID_KEY */,
53724
+ message: `Cannot set '${key}' directly. Use 'bb auth login' to configure authentication.`,
53725
+ context: { key }
53726
+ });
53498
53727
  }
53499
53728
  if (!isSettableConfigKey(key)) {
53500
- throw new Error(`Unknown config key '${key}'. Valid keys: ${SETTABLE_CONFIG_KEYS.join(", ")}`);
53729
+ throw new BBError({
53730
+ code: 4003 /* CONFIG_INVALID_KEY */,
53731
+ message: `Unknown config key '${key}'. Valid keys: ${SETTABLE_CONFIG_KEYS.join(", ")}`,
53732
+ context: { key }
53733
+ });
53501
53734
  }
53502
53735
  const parsedValue = parseSettableConfigValue(key, value);
53503
53736
  await this.configService.setValue(key, parsedValue);
@@ -53591,7 +53824,11 @@ class InstallCompletionCommand extends BaseCommand {
53591
53824
  this.output.success("Shell completions installed successfully!");
53592
53825
  this.output.text("Restart your shell or source your profile to enable completions.");
53593
53826
  } catch (error) {
53594
- throw new Error(`Failed to install completions: ${error}`);
53827
+ throw new BBError({
53828
+ code: 9999 /* UNKNOWN */,
53829
+ message: `Failed to install completions: ${error}`,
53830
+ cause: error instanceof Error ? error : undefined
53831
+ });
53595
53832
  }
53596
53833
  }
53597
53834
  }
@@ -53622,7 +53859,11 @@ class UninstallCompletionCommand extends BaseCommand {
53622
53859
  }
53623
53860
  this.output.success("Shell completions uninstalled successfully!");
53624
53861
  } catch (error) {
53625
- throw new Error(`Failed to uninstall completions: ${error}`);
53862
+ throw new BBError({
53863
+ code: 9999 /* UNKNOWN */,
53864
+ message: `Failed to uninstall completions: ${error}`,
53865
+ cause: error instanceof Error ? error : undefined
53866
+ });
53626
53867
  }
53627
53868
  }
53628
53869
  }
@@ -54041,7 +54282,7 @@ prCmd.command("checkout <id>").description("Checkout a pull request locally").ac
54041
54282
  const context = createContext(cli);
54042
54283
  await runCommand(ServiceTokens.CheckoutPRCommand, withGlobalOptions({ id, ...options }, context), cli, context);
54043
54284
  });
54044
- prCmd.command("diff [id]").description("View pull request diff").option("--color <when>", "Colorize output (auto, always, never)", "auto").option("--name-only", "Show only names of changed files").option("--stat", "Show diffstat").option("-w, --web", "Open diff in web browser").action(async (id, options) => {
54285
+ prCmd.command("diff [id]").description("View pull request diff").option("--color <when>", "Colorize output (auto, always, never)", "auto").option("--name-only", "Show only names of changed files").option("--stat", "Show diffstat").option("--web", "Open diff in web browser").action(async (id, options) => {
54045
54286
  const context = createContext(cli);
54046
54287
  await runCommand(ServiceTokens.DiffPRCommand, withGlobalOptions({ id, ...options }, context), cli, context);
54047
54288
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilatos/bitbucket-cli",
3
- "version": "1.8.0",
3
+ "version": "1.8.1",
4
4
  "description": "A command-line interface for Bitbucket Cloud",
5
5
  "author": "",
6
6
  "license": "MIT",