@pilatos/bitbucket-cli 1.9.1 → 1.10.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 +89 -41
  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;
@@ -18252,6 +18285,45 @@ function extractErrorMessage(data) {
18252
18285
  }
18253
18286
  return;
18254
18287
  }
18288
+ // src/services/reviewer.service.ts
18289
+ function extractReviewerUuids(reviewers) {
18290
+ if (!reviewers) {
18291
+ return [];
18292
+ }
18293
+ const list = Array.from(reviewers);
18294
+ const uuids = [];
18295
+ for (const reviewer of list) {
18296
+ if (reviewer.uuid) {
18297
+ uuids.push(reviewer.uuid);
18298
+ }
18299
+ }
18300
+ return uuids;
18301
+ }
18302
+ function buildReviewersUpdateBody(uuids) {
18303
+ const body = {
18304
+ type: "pullrequest",
18305
+ reviewers: uuids.map((uuid) => ({ type: "user", uuid }))
18306
+ };
18307
+ return body;
18308
+ }
18309
+ async function updatePullRequestReviewers(pullrequestsApi, repoContext, prId, transformUuids) {
18310
+ const prResponse = await pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
18311
+ workspace: repoContext.workspace,
18312
+ repoSlug: repoContext.repoSlug,
18313
+ pullRequestId: prId
18314
+ });
18315
+ const pr = prResponse.data;
18316
+ const currentUuids = extractReviewerUuids(pr.reviewers);
18317
+ const updatedUuids = transformUuids(currentUuids);
18318
+ const body = buildReviewersUpdateBody(updatedUuids);
18319
+ const response = await pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
18320
+ workspace: repoContext.workspace,
18321
+ repoSlug: repoContext.repoSlug,
18322
+ pullRequestId: prId,
18323
+ body
18324
+ });
18325
+ return response.data;
18326
+ }
18255
18327
  // src/bootstrap.ts
18256
18328
  import { createRequire } from "module";
18257
18329
 
@@ -23164,25 +23236,11 @@ class AddReviewerPRCommand extends BaseCommand {
23164
23236
  selectedUser: options.username
23165
23237
  });
23166
23238
  const user = userResponse.data;
23167
- const prResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
23168
- workspace: repoContext.workspace,
23169
- repoSlug: repoContext.repoSlug,
23170
- pullRequestId: prId
23171
- });
23172
- const pr = prResponse.data;
23173
- const existingReviewers = pr.reviewers ? Array.from(pr.reviewers) : [];
23174
- const reviewerUuids = existingReviewers.map((r) => r.uuid).filter(Boolean);
23175
- if (!reviewerUuids.includes(user.uuid)) {
23176
- reviewerUuids.push(user.uuid);
23177
- }
23178
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
23179
- workspace: repoContext.workspace,
23180
- repoSlug: repoContext.repoSlug,
23181
- pullRequestId: prId,
23182
- body: {
23183
- type: "pullrequest",
23184
- reviewers: reviewerUuids.map((uuid) => ({ uuid }))
23239
+ const updatedPr = await updatePullRequestReviewers(this.pullrequestsApi, repoContext, prId, (uuids) => {
23240
+ if (!uuids.includes(user.uuid)) {
23241
+ return [...uuids, user.uuid];
23185
23242
  }
23243
+ return uuids;
23186
23244
  });
23187
23245
  if (context.globalOptions.json) {
23188
23246
  this.output.json({
@@ -23192,7 +23250,7 @@ class AddReviewerPRCommand extends BaseCommand {
23192
23250
  username: options.username,
23193
23251
  uuid: user.uuid
23194
23252
  },
23195
- pullRequest: response.data
23253
+ pullRequest: updatedPr
23196
23254
  });
23197
23255
  return;
23198
23256
  }
@@ -23223,23 +23281,7 @@ class RemoveReviewerPRCommand extends BaseCommand {
23223
23281
  selectedUser: options.username
23224
23282
  });
23225
23283
  const user = userResponse.data;
23226
- const prResponse = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdGet({
23227
- workspace: repoContext.workspace,
23228
- repoSlug: repoContext.repoSlug,
23229
- pullRequestId: prId
23230
- });
23231
- const pr = prResponse.data;
23232
- const existingReviewers = pr.reviewers ? Array.from(pr.reviewers) : [];
23233
- const reviewerUuids = existingReviewers.map((r) => r.uuid).filter((uuid) => uuid && uuid !== user.uuid);
23234
- const response = await this.pullrequestsApi.repositoriesWorkspaceRepoSlugPullrequestsPullRequestIdPut({
23235
- workspace: repoContext.workspace,
23236
- repoSlug: repoContext.repoSlug,
23237
- pullRequestId: prId,
23238
- body: {
23239
- type: "pullrequest",
23240
- reviewers: reviewerUuids.map((uuid) => ({ uuid }))
23241
- }
23242
- });
23284
+ const updatedPr = await updatePullRequestReviewers(this.pullrequestsApi, repoContext, prId, (uuids) => uuids.filter((uuid) => uuid !== user.uuid));
23243
23285
  if (context.globalOptions.json) {
23244
23286
  this.output.json({
23245
23287
  success: true,
@@ -23248,7 +23290,7 @@ class RemoveReviewerPRCommand extends BaseCommand {
23248
23290
  username: options.username,
23249
23291
  uuid: user.uuid
23250
23292
  },
23251
- pullRequest: response.data
23293
+ pullRequest: updatedPr
23252
23294
  });
23253
23295
  return;
23254
23296
  }
@@ -23975,11 +24017,17 @@ function createContext(program2) {
23975
24017
  };
23976
24018
  }
23977
24019
  async function runCommand(token, options, program2, context) {
23978
- const cmd = container.resolve(token);
23979
- const resolvedContext = context ?? createContext(program2);
23980
24020
  try {
24021
+ const cmd = container.resolve(token);
24022
+ const resolvedContext = context ?? createContext(program2);
23981
24023
  return await cmd.run(options, resolvedContext);
23982
- } catch {
24024
+ } catch (error) {
24025
+ if (error instanceof Error && error.message.startsWith("Service not registered")) {
24026
+ console.error(`Internal error: ${error.message}`);
24027
+ }
24028
+ if (!process.exitCode) {
24029
+ process.exitCode = 1;
24030
+ }
23983
24031
  return;
23984
24032
  }
23985
24033
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pilatos/bitbucket-cli",
3
- "version": "1.9.1",
3
+ "version": "1.10.1",
4
4
  "description": "A command-line interface for Bitbucket Cloud",
5
5
  "author": "",
6
6
  "license": "MIT",