Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
35 changes: 34 additions & 1 deletion lib/modules/platform/bitbucket-server/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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')
Expand Down
13 changes: 10 additions & 3 deletions lib/modules/platform/bitbucket-server/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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'),
});
Expand Down Expand Up @@ -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;
}
Expand Down
8 changes: 5 additions & 3 deletions lib/modules/platform/bitbucket-server/readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -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` or `password` in your `config.js` file
- Set your HTTP access token as an environment variable `RENOVATE_TOKEN` or `RENOVATE_PASSWORD`
- Set your HTTP access token when you run Renovate in the CLI with `--token=` or `--password=`
Gagarmel marked this conversation as resolved.
Show resolved Hide resolved
Gagarmel marked this conversation as resolved.
Show resolved Hide resolved

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.

Expand Down
27 changes: 27 additions & 0 deletions lib/modules/platform/bitbucket-server/utils.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import type {
} from './types';
import {
BITBUCKET_INVALID_REVIEWERS_EXCEPTION,
getExtraCloneOpts,
getInvalidReviewers,
getRepoGitUrl,
} from './utils';
Expand Down Expand Up @@ -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',
});
});
});
Expand Down
19 changes: 15 additions & 4 deletions lib/modules/platform/bitbucket-server/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,11 @@ 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';
import { addSecretForSanitizing } from '../../../util/sanitize';
import { parseUrl } from '../../../util/url';
import { getPrBodyStruct } from '../pr-body';
import type { GitUrlOption } from '../types';
Expand Down Expand Up @@ -174,9 +175,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();
}

Expand Down Expand Up @@ -208,3 +210,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 {};
}