@pilatos/bitbucket-cli 1.9.0 → 1.10.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 +81 -14
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -18187,6 +18187,24 @@ var axios_default = axios;
18187
18187
 
18188
18188
  // src/services/api-client.service.ts
18189
18189
  var BASE_URL = "https://api.bitbucket.org/2.0";
18190
+ var MAX_RETRIES = 3;
18191
+ var BASE_DELAY_MS = 1000;
18192
+ var RETRYABLE_STATUS_CODES = new Set([429, 502, 503, 504]);
18193
+ function getRetryDelay(error, attempt) {
18194
+ if (error.response?.status === 429) {
18195
+ const retryAfter = error.response.headers["retry-after"];
18196
+ if (retryAfter) {
18197
+ const seconds = Number.parseInt(retryAfter, 10);
18198
+ if (!Number.isNaN(seconds)) {
18199
+ return seconds * 1000;
18200
+ }
18201
+ }
18202
+ }
18203
+ return BASE_DELAY_MS * Math.pow(2, attempt - 1);
18204
+ }
18205
+ function sleep(ms) {
18206
+ return new Promise((resolve) => setTimeout(resolve, ms));
18207
+ }
18190
18208
  function createApiClient(configService) {
18191
18209
  const instance = axios_default.create({
18192
18210
  baseURL: BASE_URL,
@@ -18210,13 +18228,28 @@ function createApiClient(configService) {
18210
18228
  console.debug(`[HTTP] Response Body:`, JSON.stringify(response.data, null, 2));
18211
18229
  }
18212
18230
  return response;
18213
- }, (error) => {
18231
+ }, async (error) => {
18214
18232
  if (process.env.DEBUG === "true") {
18215
18233
  console.debug(`[HTTP] Error:`, error.message);
18216
18234
  if (error.response) {
18217
18235
  console.debug(`[HTTP] Error Response Body:`, JSON.stringify(error.response.data, null, 2));
18218
18236
  }
18219
18237
  }
18238
+ if (error.response && RETRYABLE_STATUS_CODES.has(error.response.status)) {
18239
+ const config = error.config;
18240
+ if (config) {
18241
+ const retryCount = config.__retryCount ?? 0;
18242
+ if (retryCount < MAX_RETRIES) {
18243
+ config.__retryCount = retryCount + 1;
18244
+ const delay = getRetryDelay(error, config.__retryCount);
18245
+ const status = error.response.status;
18246
+ const label = status === 429 ? "Rate limited" : `Server error (${status})`;
18247
+ console.error(`${label}, retrying in ${(delay / 1000).toFixed(1)}s (attempt ${config.__retryCount}/${MAX_RETRIES})...`);
18248
+ await sleep(delay);
18249
+ return instance(config);
18250
+ }
18251
+ }
18252
+ }
18220
18253
  if (error.response) {
18221
18254
  const { status, data } = error.response;
18222
18255
  const message = extractErrorMessage(data) || error.message;
@@ -21124,6 +21157,27 @@ class BaseCommand {
21124
21157
  }
21125
21158
  return value;
21126
21159
  }
21160
+ parseIntOption(value, name) {
21161
+ const parsed = Number.parseInt(value, 10);
21162
+ if (Number.isNaN(parsed)) {
21163
+ throw new BBError({
21164
+ code: 5002 /* VALIDATION_INVALID */,
21165
+ message: `--${name} must be a valid integer`,
21166
+ context: { [name]: value }
21167
+ });
21168
+ }
21169
+ return parsed;
21170
+ }
21171
+ parseEnumOption(value, name, allowed) {
21172
+ if (!allowed.includes(value)) {
21173
+ throw new BBError({
21174
+ code: 5002 /* VALIDATION_INVALID */,
21175
+ message: `--${name} must be one of: ${allowed.join(", ")}`,
21176
+ context: { [name]: value }
21177
+ });
21178
+ }
21179
+ return value;
21180
+ }
21127
21181
  }
21128
21182
 
21129
21183
  // src/commands/auth/login.command.ts
@@ -21641,7 +21695,8 @@ class CreateRepoCommand extends BaseCommand {
21641
21695
  this.configService = configService;
21642
21696
  }
21643
21697
  async execute(options, context) {
21644
- const { name, description, project } = options;
21698
+ const { description, project } = options;
21699
+ const name = this.requireOption(options.name, "name");
21645
21700
  const isPublic = options.public === true;
21646
21701
  const workspace = await this.resolveWorkspace(options.workspace);
21647
21702
  const request = {
@@ -21979,7 +22034,13 @@ class ListPRsCommand extends BaseCommand {
21979
22034
  ...context.globalOptions,
21980
22035
  ...options
21981
22036
  });
21982
- const state = options.state || "OPEN";
22037
+ const ALLOWED_STATES = [
22038
+ "OPEN",
22039
+ "MERGED",
22040
+ "DECLINED",
22041
+ "SUPERSEDED"
22042
+ ];
22043
+ const state = options.state ? this.parseEnumOption(options.state, "state", ALLOWED_STATES) : "OPEN";
21983
22044
  const limit = parseLimit(options.limit);
21984
22045
  const reviewerQuery = options.mine ? await this.buildMineFilter() : undefined;
21985
22046
  const values = await collectPages({
@@ -22994,7 +23055,7 @@ class ListCommentsPRCommand extends BaseCommand {
22994
23055
  ...context.globalOptions,
22995
23056
  ...options
22996
23057
  });
22997
- const prId = Number.parseInt(options.id, 10);
23058
+ const prId = this.parseIntOption(options.id, "id");
22998
23059
  const limit = parseLimit(options.limit);
22999
23060
  const values = await collectPages({
23000
23061
  limit,
@@ -23050,8 +23111,8 @@ class EditCommentPRCommand extends BaseCommand {
23050
23111
  ...context.globalOptions,
23051
23112
  ...options
23052
23113
  });
23053
- const prId = Number.parseInt(options.prId, 10);
23054
- const commentId = Number.parseInt(options.commentId, 10);
23114
+ const prId = this.parseIntOption(options.prId, "pr-id");
23115
+ const commentId = this.parseIntOption(options.commentId, "comment-id");
23055
23116
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdCommentsCommentIdPut({
23056
23117
  workspace: repoContext.workspace,
23057
23118
  repoSlug: repoContext.repoSlug,
@@ -23093,8 +23154,8 @@ class DeleteCommentPRCommand extends BaseCommand {
23093
23154
  ...context.globalOptions,
23094
23155
  ...options
23095
23156
  });
23096
- const prId = Number.parseInt(options.prId, 10);
23097
- const commentId = Number.parseInt(options.commentId, 10);
23157
+ const prId = this.parseIntOption(options.prId, "pr-id");
23158
+ const commentId = this.parseIntOption(options.commentId, "comment-id");
23098
23159
  await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdCommentsCommentIdDelete({
23099
23160
  workspace: repoContext.workspace,
23100
23161
  repoSlug: repoContext.repoSlug,
@@ -23131,7 +23192,7 @@ class AddReviewerPRCommand extends BaseCommand {
23131
23192
  ...context.globalOptions,
23132
23193
  ...options
23133
23194
  });
23134
- const prId = Number.parseInt(options.id, 10);
23195
+ const prId = this.parseIntOption(options.id, "id");
23135
23196
  const userResponse = await this.usersApi.usersSelectedUserGet({
23136
23197
  selectedUser: options.username
23137
23198
  });
@@ -23190,7 +23251,7 @@ class RemoveReviewerPRCommand extends BaseCommand {
23190
23251
  ...context.globalOptions,
23191
23252
  ...options
23192
23253
  });
23193
- const prId = Number.parseInt(options.id, 10);
23254
+ const prId = this.parseIntOption(options.id, "id");
23194
23255
  const userResponse = await this.usersApi.usersSelectedUserGet({
23195
23256
  selectedUser: options.username
23196
23257
  });
@@ -23244,7 +23305,7 @@ class ListReviewersPRCommand extends BaseCommand {
23244
23305
  ...context.globalOptions,
23245
23306
  ...options
23246
23307
  });
23247
- const prId = Number.parseInt(options.id, 10);
23308
+ const prId = this.parseIntOption(options.id, "id");
23248
23309
  const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
23249
23310
  workspace: repoContext.workspace,
23250
23311
  repoSlug: repoContext.repoSlug,
@@ -23947,11 +24008,17 @@ function createContext(program2) {
23947
24008
  };
23948
24009
  }
23949
24010
  async function runCommand(token, options, program2, context) {
23950
- const cmd = container.resolve(token);
23951
- const resolvedContext = context ?? createContext(program2);
23952
24011
  try {
24012
+ const cmd = container.resolve(token);
24013
+ const resolvedContext = context ?? createContext(program2);
23953
24014
  return await cmd.run(options, resolvedContext);
23954
- } catch {
24015
+ } catch (error) {
24016
+ if (error instanceof Error && error.message.startsWith("Service not registered")) {
24017
+ console.error(`Internal error: ${error.message}`);
24018
+ }
24019
+ if (!process.exitCode) {
24020
+ process.exitCode = 1;
24021
+ }
23955
24022
  return;
23956
24023
  }
23957
24024
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilatos/bitbucket-cli",
3
- "version": "1.9.0",
3
+ "version": "1.10.0",
4
4
  "description": "A command-line interface for Bitbucket Cloud",
5
5
  "author": "",
6
6
  "license": "MIT",