feat(bitbucket-server): Add bitbucket http access token support (#28093)

Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
This commit is contained in:
Gagarmel 2024-04-12 09:17:44 +02:00 committed by GitHub
parent 1f805b25db
commit 771b91f69f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 90 additions and 11 deletions

View file

@ -247,13 +247,46 @@ describe('modules/platform/bitbucket-server/index', () => {
await expect(bitbucket.initPlatform({})).rejects.toThrow();
});
it('should throw if no username/password', async () => {
it('should throw if no username/password/token', async () => {
expect.assertions(1);
await expect(
bitbucket.initPlatform({ endpoint: 'endpoint' }),
).rejects.toThrow();
});
it('should throw if password and token is set', async () => {
expect.assertions(1);
await expect(
bitbucket.initPlatform({
endpoint: 'endpoint',
username: 'abc',
password: '123',
token: 'abc',
}),
).rejects.toThrow();
});
it('should not throw if username/password', async () => {
expect.assertions(1);
await expect(
bitbucket.initPlatform({
endpoint: 'endpoint',
username: 'abc',
password: '123',
}),
).resolves.not.toThrow();
});
it('should not throw if token', async () => {
expect.assertions(1);
await expect(
bitbucket.initPlatform({
endpoint: 'endpoint',
token: 'abc',
}),
).resolves.not.toThrow();
});
it('should throw if version could not be fetched', async () => {
httpMock
.scope('https://stash.renovatebot.com')

View file

@ -49,6 +49,7 @@ import type {
BbsRestUserRef,
} from './types';
import * as utils from './utils';
import { getExtraCloneOpts } from './utils';
/*
* Version: 5.3 (EOL Date: 15 Aug 2019)
@ -84,15 +85,20 @@ function updatePrVersion(pr: number, version: number): number {
export async function initPlatform({
endpoint,
token,
username,
password,
}: PlatformParams): Promise<PlatformResult> {
if (!endpoint) {
throw new Error('Init: You must configure a Bitbucket Server endpoint');
}
if (!(username && password)) {
if (!(username && password) && !token) {
throw new Error(
'Init: You must configure a Bitbucket Server username/password',
'Init: You must either configure a Bitbucket Server username/password or a HTTP access token',
);
} else if (password && token) {
throw new Error(
'Init: You must either configure a Bitbucket Server password or a HTTP access token',
);
}
// TODO: Add a connection check that endpoint/username/password combination are valid (#9595)
@ -231,6 +237,7 @@ export async function initRepo({
await git.initRepo({
...config,
url,
extraCloneOpts: getExtraCloneOpts(opts),
cloneSubmodules,
fullClone: semver.lte(defaults.version, '8.0.0'),
});
@ -328,7 +335,7 @@ export async function getPrList(refreshCache?: boolean): Promise<Pr[]> {
const searchParams: Record<string, string> = {
state: 'ALL',
};
if (!config.ignorePrAuthor) {
if (!config.ignorePrAuthor && config.username !== undefined) {
searchParams['role.1'] = 'AUTHOR';
searchParams['username.1'] = config.username;
}

View file

@ -5,9 +5,11 @@
First, create a [HTTP access token](https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html) for the bot account.
Let Renovate use your HTTP access token by doing _one_ of the following:
- Set your HTTP access token as a `password` in your `config.js` file
- Set your HTTP access token as an environment variable `RENOVATE_PASSWORD`
- Set your HTTP access token when you run Renovate in the CLI with `--password=`
- Set your HTTP access token as a `token` in your `config.js` file
- Set your HTTP access token as an environment variable `RENOVATE_TOKEN`
- Set your HTTP access token when you run Renovate in the CLI with `--token=`
If you use project or repository based HTTP access tokens, it can only be used as `token`.
Remember to set `platform=bitbucket-server` somewhere in your Renovate config file.

View file

@ -8,6 +8,7 @@ import type {
} from './types';
import {
BITBUCKET_INVALID_REVIEWERS_EXCEPTION,
getExtraCloneOpts,
getInvalidReviewers,
getRepoGitUrl,
} from './utils';
@ -268,6 +269,32 @@ describe('modules/platform/bitbucket-server/utils', () => {
),
);
});
it('works gitUrl:endpoint no basic auth', () => {
expect(
getRepoGitUrl(
'SOME/repo',
url.toString(),
'endpoint',
infoMock(url, 'SOME', 'repo'),
{},
),
).toBe(httpLink(url.toString(), 'SOME', 'repo'));
});
});
});
});
describe('getExtraCloneOpts', () => {
it('should not configure bearer token', () => {
const res = getExtraCloneOpts({});
expect(res).toEqual({});
});
it('should configure bearer token', () => {
const res = getExtraCloneOpts({ token: 'abc' });
expect(res).toEqual({
'-c': 'http.extraheader=Authorization: Bearer abc',
});
});
});

View file

@ -4,7 +4,7 @@ import is from '@sindresorhus/is';
import { CONFIG_GIT_URL_UNAVAILABLE } from '../../../constants/error-messages';
import { logger } from '../../../logger';
import type { HostRule } from '../../../types';
import type { GitProtocol } from '../../../types/git';
import type { GitOptions, GitProtocol } from '../../../types/git';
import * as git from '../../../util/git';
import { BitbucketServerHttp } from '../../../util/http/bitbucket-server';
import type { HttpOptions, HttpResponse } from '../../../util/http/types';
@ -174,9 +174,10 @@ function injectAuth(url: string, opts: HostRule): string {
logger.debug(`Invalid url: ${url}`);
throw new Error(CONFIG_GIT_URL_UNAVAILABLE);
}
// TODO: null checks (#22198)
repoUrl.username = opts.username!;
repoUrl.password = opts.password!;
if (!opts.token && opts.username && opts.password) {
repoUrl.username = opts.username;
repoUrl.password = opts.password;
}
return repoUrl.toString();
}
@ -208,3 +209,12 @@ export function getRepoGitUrl(
// SSH urls can be used directly
return cloneUrl.href;
}
export function getExtraCloneOpts(opts: HostRule): GitOptions {
if (opts.token) {
return {
'-c': `http.extraheader=Authorization: Bearer ${opts.token}`,
};
}
return {};
}