@@ -13,7 +13,7 @@ import {
1313 RequestClientError ,
1414 RequestNotFoundError ,
1515} from '../../../../errors' ;
16- import type { IssueOrPullRequest } from '../../../../git/models/issueOrPullRequest' ;
16+ import type { IssueOrPullRequest , IssueOrPullRequestType } from '../../../../git/models/issueOrPullRequest' ;
1717import type { PullRequest } from '../../../../git/models/pullRequest' ;
1818import type { Provider } from '../../../../git/models/remoteProvider' ;
1919import { showIntegrationRequestFailed500WarningMessage } from '../../../../messages' ;
@@ -23,8 +23,8 @@ import { Logger } from '../../../../system/logger';
2323import type { LogScope } from '../../../../system/logger.scope' ;
2424import { getLogScope } from '../../../../system/logger.scope' ;
2525import { maybeStopWatch } from '../../../../system/stopwatch' ;
26- import type { BitbucketPullRequest } from './models' ;
27- import { fromBitbucketPullRequest } from './models' ;
26+ import type { BitbucketIssue , BitbucketPullRequest } from './models' ;
27+ import { bitbucketIssueStateToState , fromBitbucketPullRequest } from './models' ;
2828
2929export class BitbucketApi implements Disposable {
3030 private readonly _disposable : Disposable ;
@@ -102,25 +102,69 @@ export class BitbucketApi implements Disposable {
102102 id : string ,
103103 options : {
104104 baseUrl : string ;
105+ type ?: IssueOrPullRequestType ;
105106 } ,
106107 ) : Promise < IssueOrPullRequest | undefined > {
107108 const scope = getLogScope ( ) ;
108109
109- const response = await this . request < BitbucketPullRequest > (
110- provider ,
111- token ,
112- options . baseUrl ,
113- `repositories/${ owner } /${ repo } /pullrequests/${ id } ?fields=*` ,
114- {
115- method : 'GET' ,
116- } ,
117- scope ,
118- ) ;
110+ if ( options ?. type !== 'issue' ) {
111+ try {
112+ const prResponse = await this . request < BitbucketPullRequest > (
113+ provider ,
114+ token ,
115+ options . baseUrl ,
116+ `repositories/${ owner } /${ repo } /pullrequests/${ id } ?fields=%2Bvalues.reviewers,%2Bvalues.participants` ,
117+ {
118+ method : 'GET' ,
119+ } ,
120+ scope ,
121+ ) ;
119122
120- if ( ! response ) {
121- return undefined ;
123+ if ( prResponse ) {
124+ return fromBitbucketPullRequest ( prResponse , provider ) ;
125+ }
126+ } catch ( ex ) {
127+ if ( ex . original ?. status !== 404 ) {
128+ Logger . error ( ex , scope ) ;
129+ return undefined ;
130+ }
131+ }
122132 }
123- return fromBitbucketPullRequest ( response , provider ) ;
133+
134+ if ( options ?. type !== 'pullrequest' ) {
135+ try {
136+ const issueResponse = await this . request < BitbucketIssue > (
137+ provider ,
138+ token ,
139+ options . baseUrl ,
140+ `repositories/${ owner } /${ repo } /issues/${ id } ` ,
141+ {
142+ method : 'GET' ,
143+ } ,
144+ scope ,
145+ ) ;
146+
147+ if ( issueResponse ) {
148+ return {
149+ id : issueResponse . id . toString ( ) ,
150+ type : 'issue' ,
151+ nodeId : issueResponse . id . toString ( ) ,
152+ provider : provider ,
153+ createdDate : new Date ( issueResponse . created_on ) ,
154+ updatedDate : new Date ( issueResponse . updated_on ) ,
155+ state : bitbucketIssueStateToState ( issueResponse . state ) ,
156+ closed : issueResponse . state === 'closed' ,
157+ title : issueResponse . title ,
158+ url : issueResponse . links . html . href ,
159+ } ;
160+ }
161+ } catch ( ex ) {
162+ Logger . error ( ex , scope ) ;
163+ return undefined ;
164+ }
165+ }
166+
167+ return undefined ;
124168 }
125169
126170 private async request < T > (
@@ -192,22 +236,22 @@ export class BitbucketApi implements Disposable {
192236 throw new RequestNotFoundError ( ex ) ;
193237 case 401 : // Unauthorized
194238 throw new AuthenticationError ( 'bitbucket' , AuthenticationErrorReason . Unauthorized , ex ) ;
195- // TODO: Learn the Bitbucket API docs and put it in order:
196- // case 403: // Forbidden
197- // if (ex.message.includes('rate limit')) {
198- // let resetAt: number | undefined;
199-
200- // const reset = ex.response?.headers?.get('x-ratelimit-reset');
201- // if (reset != null) {
202- // resetAt = parseInt(reset, 10);
203- // if (Number.isNaN(resetAt)) {
204- // resetAt = undefined;
205- // }
206- // }
207-
208- // throw new RequestRateLimitError(ex, token, resetAt);
209- // }
210- // throw new AuthenticationError('bitbucket', AuthenticationErrorReason.Forbidden, ex);
239+ case 403 : // Forbidden
240+ // TODO: Learn the Bitbucket API docs and put it in order:
241+ // if (ex.message.includes('rate limit')) {
242+ // let resetAt: number | undefined;
243+
244+ // const reset = ex.response?.headers?.get('x-ratelimit-reset');
245+ // if (reset != null) {
246+ // resetAt = parseInt(reset, 10);
247+ // if (Number.isNaN(resetAt)) {
248+ // resetAt = undefined;
249+ // }
250+ // }
251+
252+ // throw new RequestRateLimitError(ex, token, resetAt);
253+ // }
254+ throw new AuthenticationError ( 'bitbucket' , AuthenticationErrorReason . Forbidden , ex ) ;
211255 case 500 : // Internal Server Error
212256 Logger . error ( ex , scope ) ;
213257 if ( ex . response != null ) {
0 commit comments