Provisioning: Fix loading bitbucket branches (#110651)

* Provisioning: Fetch bitbucket branches

* reuse func

* Prettier
This commit is contained in:
Alex Khomenko
2025-09-05 07:42:43 +00:00
committed by GitHub
parent f347bb4f61
commit a8378af6ed
3 changed files with 33 additions and 19 deletions
@@ -25,7 +25,11 @@ export function ConnectStep() {
// We don't need to dynamically react on repo type changes, so we use getValues for it
const type = getValues('repository.type');
const [repositoryUrl = '', repositoryToken = ''] = watch(['repository.url', 'repository.token']);
const [repositoryUrl = '', repositoryToken = '', repositoryTokenUser = ''] = watch([
'repository.url',
'repository.token',
'repository.tokenUser',
]);
const isGitBased = isGitProvider(type);
const {
@@ -36,6 +40,7 @@ export function ConnectStep() {
repositoryType: type,
repositoryUrl,
repositoryToken,
repositoryTokenUser,
});
const gitFields = isGitBased ? getGitProviderFields(type) : null;
@@ -14,11 +14,18 @@ export interface UseBranchOptionsProps {
repositoryType: RepoType;
repositoryUrl: string;
repositoryToken: string;
repositoryTokenUser?: string;
}
export function useBranchOptions({ repositoryType, repositoryUrl = '', repositoryToken = '' }: UseBranchOptionsProps) {
export function useBranchOptions({
repositoryType,
repositoryUrl = '',
repositoryToken = '',
repositoryTokenUser = '',
}: UseBranchOptionsProps) {
const trimmedUrl = repositoryUrl.trim();
const trimmedToken = repositoryToken.trim();
const trimmedTokenUser = repositoryTokenUser.trim();
const hasRequiredData = useMemo(() => {
if (!isSupportedGitProvider(repositoryType)) {
@@ -27,10 +34,11 @@ export function useBranchOptions({ repositoryType, repositoryUrl = '', repositor
const hasUrl = trimmedUrl.length > 0;
const hasToken = trimmedToken.length > 0;
const hasTokenUser = repositoryType === 'bitbucket' ? trimmedTokenUser.length > 0 : true;
const repoInfo = hasUrl ? parseRepositoryUrl(trimmedUrl, repositoryType) : null;
return hasUrl && hasToken && repoInfo !== null;
}, [trimmedUrl, trimmedToken, repositoryType]);
return hasUrl && hasToken && hasTokenUser && repoInfo !== null;
}, [trimmedUrl, trimmedToken, trimmedTokenUser, repositoryType]);
const fetchOptions = useMemo(
() => async (): Promise<Array<{ label: string; value: string }>> => {
@@ -44,14 +52,16 @@ export function useBranchOptions({ repositoryType, repositoryUrl = '', repositor
throw new Error('Invalid repository URL format');
}
const branchData = await fetchAllBranches(repositoryType, repoInfo.owner, repoInfo.repo, trimmedToken);
// For Bitbucket, combine username and app password for Basic auth
const authToken = repositoryType === 'bitbucket' ? `${trimmedTokenUser}:${trimmedToken}` : trimmedToken;
const branchData = await fetchAllBranches(repositoryType, repoInfo.owner, repoInfo.repo, authToken);
return branchData.map((branch) => ({
label: branch.name,
value: branch.name,
}));
},
[hasRequiredData, trimmedUrl, trimmedToken, repositoryType]
[hasRequiredData, trimmedUrl, trimmedToken, trimmedTokenUser, repositoryType]
);
const asyncState = useAsync(fetchOptions, [fetchOptions]);
@@ -50,7 +50,7 @@ export function getProviderHeaders(repositoryType: string, token: string): Recor
case 'gitlab':
return { 'Private-Token': token };
case 'bitbucket':
return { Authorization: `Bearer ${token}` };
return { Authorization: `Basic ${btoa(token)}` };
default:
throw new Error(
t('provisioning.http-utils.unsupported-repository-type', 'Unsupported repository type: {{repositoryType}}', {
@@ -82,7 +82,7 @@ export async function makeApiRequest(request: ApiRequest) {
return response.json();
}
// GitHub and GitLab limit results to 100 items per page, so we need to paginate
// GitHub, GitLab, and Bitbucket limit results to 100 items per page, so we need to paginate
async function fetchWithPagination(
buildUrl: (page: number) => string,
headers: Record<string, string>
@@ -95,9 +95,12 @@ async function fetchWithPagination(
const url = buildUrl(page);
const data = await makeApiRequest({ url, headers });
if (Array.isArray(data) && data.length > 0) {
allBranches.push(...data);
hasMorePages = data.length === 100;
// Handle GitHub/GitLab format (direct array) and Bitbucket format ({ values: [...] })
const branches = Array.isArray(data) ? data : data?.values;
if (Array.isArray(branches) && branches.length > 0) {
allBranches.push(...branches);
hasMorePages = branches.length === 100;
page++;
} else {
hasMorePages = false;
@@ -135,14 +138,10 @@ export async function fetchAllBitbucketBranches(
repo: string,
headers: Record<string, string>
): Promise<Array<{ name: string }>> {
const url = `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/refs/branches?pagelen=1000`;
const data = await makeApiRequest({ url, headers });
if (data && Array.isArray(data.values)) {
return data.values;
}
return [];
return fetchWithPagination(
(page) => `https://api.bitbucket.org/2.0/repositories/${owner}/${repo}/refs/branches?pagelen=100&page=${page}`,
headers
);
}
export async function fetchAllBranches(