mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-14 16:46:25 +00:00
feat(bitbucket-server): Add bitbucket http access token support (#28093)
Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
This commit is contained in:
parent
1f805b25db
commit
771b91f69f
5 changed files with 90 additions and 11 deletions
|
@ -247,13 +247,46 @@ describe('modules/platform/bitbucket-server/index', () => {
|
||||||
await expect(bitbucket.initPlatform({})).rejects.toThrow();
|
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);
|
expect.assertions(1);
|
||||||
await expect(
|
await expect(
|
||||||
bitbucket.initPlatform({ endpoint: 'endpoint' }),
|
bitbucket.initPlatform({ endpoint: 'endpoint' }),
|
||||||
).rejects.toThrow();
|
).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 () => {
|
it('should throw if version could not be fetched', async () => {
|
||||||
httpMock
|
httpMock
|
||||||
.scope('https://stash.renovatebot.com')
|
.scope('https://stash.renovatebot.com')
|
||||||
|
|
|
@ -49,6 +49,7 @@ import type {
|
||||||
BbsRestUserRef,
|
BbsRestUserRef,
|
||||||
} from './types';
|
} from './types';
|
||||||
import * as utils from './utils';
|
import * as utils from './utils';
|
||||||
|
import { getExtraCloneOpts } from './utils';
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Version: 5.3 (EOL Date: 15 Aug 2019)
|
* Version: 5.3 (EOL Date: 15 Aug 2019)
|
||||||
|
@ -84,15 +85,20 @@ function updatePrVersion(pr: number, version: number): number {
|
||||||
|
|
||||||
export async function initPlatform({
|
export async function initPlatform({
|
||||||
endpoint,
|
endpoint,
|
||||||
|
token,
|
||||||
username,
|
username,
|
||||||
password,
|
password,
|
||||||
}: PlatformParams): Promise<PlatformResult> {
|
}: PlatformParams): Promise<PlatformResult> {
|
||||||
if (!endpoint) {
|
if (!endpoint) {
|
||||||
throw new Error('Init: You must configure a Bitbucket Server endpoint');
|
throw new Error('Init: You must configure a Bitbucket Server endpoint');
|
||||||
}
|
}
|
||||||
if (!(username && password)) {
|
if (!(username && password) && !token) {
|
||||||
throw new Error(
|
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)
|
// TODO: Add a connection check that endpoint/username/password combination are valid (#9595)
|
||||||
|
@ -231,6 +237,7 @@ export async function initRepo({
|
||||||
await git.initRepo({
|
await git.initRepo({
|
||||||
...config,
|
...config,
|
||||||
url,
|
url,
|
||||||
|
extraCloneOpts: getExtraCloneOpts(opts),
|
||||||
cloneSubmodules,
|
cloneSubmodules,
|
||||||
fullClone: semver.lte(defaults.version, '8.0.0'),
|
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> = {
|
const searchParams: Record<string, string> = {
|
||||||
state: 'ALL',
|
state: 'ALL',
|
||||||
};
|
};
|
||||||
if (!config.ignorePrAuthor) {
|
if (!config.ignorePrAuthor && config.username !== undefined) {
|
||||||
searchParams['role.1'] = 'AUTHOR';
|
searchParams['role.1'] = 'AUTHOR';
|
||||||
searchParams['username.1'] = config.username;
|
searchParams['username.1'] = config.username;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,9 +5,11 @@
|
||||||
First, create a [HTTP access token](https://confluence.atlassian.com/bitbucketserver/personal-access-tokens-939515499.html) for the bot account.
|
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:
|
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 a `token` in your `config.js` file
|
||||||
- Set your HTTP access token as an environment variable `RENOVATE_PASSWORD`
|
- Set your HTTP access token as an environment variable `RENOVATE_TOKEN`
|
||||||
- Set your HTTP access token when you run Renovate in the CLI with `--password=`
|
- 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.
|
Remember to set `platform=bitbucket-server` somewhere in your Renovate config file.
|
||||||
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ import type {
|
||||||
} from './types';
|
} from './types';
|
||||||
import {
|
import {
|
||||||
BITBUCKET_INVALID_REVIEWERS_EXCEPTION,
|
BITBUCKET_INVALID_REVIEWERS_EXCEPTION,
|
||||||
|
getExtraCloneOpts,
|
||||||
getInvalidReviewers,
|
getInvalidReviewers,
|
||||||
getRepoGitUrl,
|
getRepoGitUrl,
|
||||||
} from './utils';
|
} 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',
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -4,7 +4,7 @@ import is from '@sindresorhus/is';
|
||||||
import { CONFIG_GIT_URL_UNAVAILABLE } from '../../../constants/error-messages';
|
import { CONFIG_GIT_URL_UNAVAILABLE } from '../../../constants/error-messages';
|
||||||
import { logger } from '../../../logger';
|
import { logger } from '../../../logger';
|
||||||
import type { HostRule } from '../../../types';
|
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 * as git from '../../../util/git';
|
||||||
import { BitbucketServerHttp } from '../../../util/http/bitbucket-server';
|
import { BitbucketServerHttp } from '../../../util/http/bitbucket-server';
|
||||||
import type { HttpOptions, HttpResponse } from '../../../util/http/types';
|
import type { HttpOptions, HttpResponse } from '../../../util/http/types';
|
||||||
|
@ -174,9 +174,10 @@ function injectAuth(url: string, opts: HostRule): string {
|
||||||
logger.debug(`Invalid url: ${url}`);
|
logger.debug(`Invalid url: ${url}`);
|
||||||
throw new Error(CONFIG_GIT_URL_UNAVAILABLE);
|
throw new Error(CONFIG_GIT_URL_UNAVAILABLE);
|
||||||
}
|
}
|
||||||
// TODO: null checks (#22198)
|
if (!opts.token && opts.username && opts.password) {
|
||||||
repoUrl.username = opts.username!;
|
repoUrl.username = opts.username;
|
||||||
repoUrl.password = opts.password!;
|
repoUrl.password = opts.password;
|
||||||
|
}
|
||||||
return repoUrl.toString();
|
return repoUrl.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -208,3 +209,12 @@ export function getRepoGitUrl(
|
||||||
// SSH urls can be used directly
|
// SSH urls can be used directly
|
||||||
return cloneUrl.href;
|
return cloneUrl.href;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function getExtraCloneOpts(opts: HostRule): GitOptions {
|
||||||
|
if (opts.token) {
|
||||||
|
return {
|
||||||
|
'-c': `http.extraheader=Authorization: Bearer ${opts.token}`,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in a new issue