-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: import data command for bitbucket cloud (#266)
* feat: import:data for Bitbucket Cloud Add support for generating import targets data file for Bitbucket Cloud by listing existing repos in users Bitbucket Cloud. * refactor: add return request types Co-authored-by: ghe <[email protected]>
- Loading branch information
Showing
24 changed files
with
428 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
9 changes: 9 additions & 0 deletions
9
src/lib/source-handlers/bitbucket-cloud/get-bitbucket-cloud-password.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export function getBitbucketCloudPassword(): string { | ||
const bitbucketCloudPassword = process.env.BITBUCKET_CLOUD_PASSWORD; | ||
if (!bitbucketCloudPassword) { | ||
throw new Error( | ||
`Please set the BITBUCKET_CLOUD_PASSWORD e.g. export BITBUCKET_CLOUD_PASSWORD='mybitbucketCloudPassword'`, | ||
); | ||
} | ||
return bitbucketCloudPassword; | ||
} |
9 changes: 9 additions & 0 deletions
9
src/lib/source-handlers/bitbucket-cloud/get-bitbucket-cloud-username.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
export function getBitbucketCloudUsername(): string { | ||
const bitbucketCLoudUsername = process.env.BITBUCKET_CLOUD_USERNAME; | ||
if (!bitbucketCLoudUsername) { | ||
throw new Error( | ||
`Please set the BITBUCKET_CLOUD_USERNAME e.g. export BITBUCKET_CLOUD_USERNAME='myBitbucketCloudUsername'`, | ||
); | ||
} | ||
return bitbucketCLoudUsername; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
export * from './list-workspaces'; | ||
export * from './list-repos'; | ||
export * from './workspace-is-empty'; | ||
export * from './types'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
import * as debugLib from 'debug'; | ||
import base64 = require('base-64'); | ||
import { OutgoingHttpHeaders } from 'http2'; | ||
import { BitbucketCloudRepoData } from './types'; | ||
import { getBitbucketCloudUsername } from './get-bitbucket-cloud-username'; | ||
import { getBitbucketCloudPassword } from './get-bitbucket-cloud-password'; | ||
import { limiterForScm } from '../../limiters'; | ||
import { limiterWithRateLimitRetries } from '../../request-with-rate-limit'; | ||
|
||
const debug = debugLib('snyk:bitbucket-cloud'); | ||
|
||
interface BitbucketReposResponse { | ||
values: { | ||
mainbranch: { | ||
name: string; | ||
}; | ||
slug: string; | ||
workspace: { | ||
slug: string; | ||
uuid: string; | ||
}; | ||
}[]; | ||
next?: string; | ||
} | ||
|
||
export const fetchAllBitbucketCloudRepos = async ( | ||
workspace: string, | ||
username: string, | ||
password: string, | ||
): Promise<BitbucketCloudRepoData[]> => { | ||
let lastPage = false; | ||
let reposList: BitbucketCloudRepoData[] = []; | ||
let pageCount = 1; | ||
let nextPage; | ||
while (!lastPage) { | ||
debug(`Fetching page ${pageCount} for ${workspace}\n`); | ||
try { | ||
const { | ||
repos, | ||
next, | ||
}: { repos: BitbucketCloudRepoData[]; next?: string } = await getRepos( | ||
workspace, | ||
username, | ||
password, | ||
nextPage, | ||
); | ||
|
||
reposList = reposList.concat(repos); | ||
next | ||
? ((lastPage = false), (nextPage = next)) | ||
: ((lastPage = true), (nextPage = '')); | ||
pageCount++; | ||
} catch (err) { | ||
throw new Error(JSON.stringify(err)); | ||
} | ||
} | ||
return reposList; | ||
}; | ||
|
||
const getRepos = async ( | ||
workspace: string, | ||
username: string, | ||
password: string, | ||
nextPageLink?: string, | ||
): Promise<{ repos: BitbucketCloudRepoData[]; next?: string }> => { | ||
const repos: BitbucketCloudRepoData[] = []; | ||
const headers: OutgoingHttpHeaders = { | ||
Authorization: `Basic ${base64.encode(username + ':' + password)}`, | ||
}; | ||
const limiter = await limiterForScm(1, 1000, 1000, 1000, 1000 * 3600); | ||
const { statusCode, body } = await limiterWithRateLimitRetries< | ||
BitbucketReposResponse | ||
>( | ||
'get', | ||
nextPageLink ?? `https://bitbucket.org/api/2.0/repositories/${workspace}`, | ||
headers, | ||
limiter, | ||
60000, | ||
); | ||
if (statusCode != 200) { | ||
throw new Error(`Failed to fetch projects for ${ | ||
nextPageLink != '' | ||
? nextPageLink | ||
: `https://bitbucket.org/api/2.0/repositories/${workspace}` | ||
}\n | ||
Status Code: ${statusCode}\n | ||
Response body: ${JSON.stringify(body)}`); | ||
} | ||
const { next, values } = body; | ||
for (const repo of values) { | ||
const { workspace, mainbranch, slug } = repo; | ||
if (mainbranch.name && workspace && slug) | ||
repos.push({ | ||
owner: workspace.slug ? workspace.slug : repo.workspace.uuid, | ||
name: slug, | ||
branch: mainbranch.name, | ||
}); | ||
} | ||
return { repos, next }; | ||
}; | ||
|
||
export async function listBitbucketCloudRepos( | ||
workspace: string, | ||
): Promise<BitbucketCloudRepoData[]> { | ||
const bitbucketCloudUsername = getBitbucketCloudUsername(); | ||
const bitbucketCloudPassword = getBitbucketCloudPassword(); | ||
debug(`Fetching all repos data for org: ${workspace}`); | ||
const repoList = await fetchAllBitbucketCloudRepos( | ||
workspace, | ||
bitbucketCloudUsername, | ||
bitbucketCloudPassword, | ||
); | ||
return repoList; | ||
} |
Oops, something went wrong.