@@ -157,8 +157,57 @@ export class BitbucketRepositoryProvider implements RepositoryProvider {
157
157
return commits . map ( ( v : Schema . Commit ) => v . hash ! ) ;
158
158
}
159
159
160
- // TODO: implement repo search
160
+ //
161
+ // Searching Bitbucket requires a workspace to be specified
162
+ // This results in a two step process:
163
+ // 1. Get all workspaces for the user
164
+ // 2. Fan out and search each workspace for the repos
165
+ //
161
166
public async searchRepos ( user : User , searchString : string ) : Promise < RepositoryInfo [ ] > {
162
- return [ ] ;
167
+ const api = await this . apiFactory . create ( user ) ;
168
+
169
+ const workspaces = await api . workspaces . getWorkspaces ( { } ) ;
170
+
171
+ const workspaceSlugs : string [ ] = (
172
+ workspaces . data . values ?. map ( ( w ) => {
173
+ return w . slug || "" ;
174
+ } ) ?? [ ]
175
+ ) . filter ( Boolean ) ;
176
+
177
+ if ( workspaceSlugs . length === 0 ) {
178
+ return [ ] ;
179
+ }
180
+
181
+ // Array of promises searching for repos in each workspace
182
+ const workspaceSearches = workspaceSlugs . map ( ( workspaceSlug ) => {
183
+ return api . repositories . list ( {
184
+ workspace : workspaceSlug ,
185
+ q : `name ~ "${ searchString } "` ,
186
+ sort : "-updated_on" ,
187
+ // limit to the first 10 results per workspace
188
+ pagelen : 10 ,
189
+ } ) ;
190
+ } ) ;
191
+
192
+ const results = await Promise . allSettled ( workspaceSearches ) ;
193
+
194
+ const values = results
195
+ . map ( ( result ) => {
196
+ return result . status === "fulfilled" ? result . value . data . values ?? [ ] : [ ] ;
197
+ } )
198
+ . flat ( ) ;
199
+
200
+ // Convert into RepositoryInfo
201
+ const repos : RepositoryInfo [ ] = [ ] ;
202
+
203
+ values . forEach ( ( repo ) => {
204
+ const name = repo . name ;
205
+ const url = repo . links ?. html ?. href ;
206
+ if ( name && url ) {
207
+ repos . push ( { name, url } ) ;
208
+ }
209
+ } ) ;
210
+
211
+ return repos ;
163
212
}
164
213
}
0 commit comments