From f18b7f3504c3bdb799f1ff15fbe977cefb24641d Mon Sep 17 00:00:00 2001 From: Michael Kriese <michael.kriese@visualon.de> Date: Wed, 9 Dec 2020 13:31:06 +0100 Subject: [PATCH] feat(gitea): support presets (#7920) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> --- docs/development/shareable-configs.md | 4 +- docs/usage/config-presets.md | 17 +- .../presets/__snapshots__/index.spec.ts.snap | 9 + .../gitea/__snapshots__/index.spec.ts.snap | 194 +++++++++++++++++ lib/config/presets/gitea/index.spec.ts | 195 ++++++++++++++++++ lib/config/presets/gitea/index.ts | 58 ++++++ lib/config/presets/index.spec.ts | 3 + lib/config/presets/index.ts | 5 + .../local/__snapshots__/index.spec.ts.snap | 24 +++ lib/config/presets/local/index.spec.ts | 26 +++ lib/config/presets/local/index.ts | 4 + lib/util/http/gitea.ts | 6 +- 12 files changed, 539 insertions(+), 6 deletions(-) create mode 100644 lib/config/presets/gitea/__snapshots__/index.spec.ts.snap create mode 100644 lib/config/presets/gitea/index.spec.ts create mode 100644 lib/config/presets/gitea/index.ts diff --git a/docs/development/shareable-configs.md b/docs/development/shareable-configs.md index 9b1058e596..906d0b0b4b 100644 --- a/docs/development/shareable-configs.md +++ b/docs/development/shareable-configs.md @@ -46,7 +46,7 @@ If you use a non-scoped config, you must use a preset name! ### Git based -In general, GitHub or GitLab-based preset hosting is easier than npm because you avoid the "publish" step - simply commit preset code to the default branch and it will be picked up by Renovate the next time it runs. +In general, GitHub, GitLab or Gitea-based preset hosting is easier than npm because you avoid the "publish" step - simply commit preset code to the default branch and it will be picked up by Renovate the next time it runs. An additional benefit of using source code hosting is that the same token/authentication can be reused by Renovate in case you want to make your config private. | name | example use | preset | resolves as | filename | @@ -55,4 +55,6 @@ An additional benefit of using source code hosting is that the same token/authen | GitHub with preset name | `github>abc/foo:xyz` | `xyz` | `https://github.com/abc/foo` | `xyz.json` | | GitLab default | `gitlab>abc/foo` | `default` | `https://gitlab.com/abc/foo` | `default.json` or `renovate.json` | | GitLab with preset name | `gitlab>abc/foo:xyz` | `xyz` | `https://gitlab.com/abc/foo` | `xyz.json` | +| Gitea default | `gitea>abc/foo` | `default` | `https://gitea.com/abc/foo` | `default.json` or `renovate.json` | +| Gitea with preset name | `gitea>abc/foo:xyz` | `xyz` | `https://gitea.com/abc/foo` | `xyz.json` | | Local default | `local>abc/foo` | `default` | `https://github.company.com/abc/foo` | `default.json` or `renovate.json` | diff --git a/docs/usage/config-presets.md b/docs/usage/config-presets.md index 701f12f10e..d67a7c08e8 100644 --- a/docs/usage/config-presets.md +++ b/docs/usage/config-presets.md @@ -30,7 +30,7 @@ In order to achieve these goals, preset configs allow for a very modular approac ## Preset Hosting -In general, GitHub or GitLab-based preset hosting is easier than npm because you avoid the "publish" step - simply commit preset code to the default branch and it will be picked up by Renovate the next time it runs. +In general, GitHub, GitLab or Gitea-based preset hosting is easier than npm because you avoid the "publish" step - simply commit preset code to the default branch and it will be picked up by Renovate the next time it runs. An additional benefit of using source code hosting is that the same token/authentication can be reused by Renovate in case you want to make your config private. | name | example use | preset | resolves as | filename | @@ -39,6 +39,8 @@ An additional benefit of using source code hosting is that the same token/authen | GitHub with preset name | `github>abc/foo:xyz` | `xyz` | `https://github.com/abc/foo` | `xyz.json` | | GitLab default | `gitlab>abc/foo` | `default` | `https://gitlab.com/abc/foo` | `default.json` or `renovate.json` | | GitLab with preset name | `gitlab>abc/foo:xyz` | `xyz` | `https://gitlab.com/abc/foo` | `xyz.json` | +| Gitea default | `gitea>abc/foo` | `default` | `https://gitea.com/abc/foo` | `default.json` or `renovate.json` | +| Gitea with preset name | `gitea>abc/foo:xyz` | `xyz` | `https://gitea.com/abc/foo` | `xyz.json` | | Local default | `local>abc/foo` | `default` | `https://github.company.com/abc/foo` | `default.json` or `renovate.json` | ## Example configs @@ -180,11 +182,22 @@ To host your preset config on GitLab: - Add a renovate.json to this new repo containing the preset config. No other files are necessary - In other repos, reference it in an extends array like "gitlab>owner/name", e.g. "gitlab>rarkins/renovate-config" +## Gitea-hosted Presets + +It is also possible to host your preset config using just a regular Gitea repository and without needing to publish it to npmjs. +In such cases Renovate will simply look for a `renovate.json` file in the default branch, (for now only the _master_ branch is supported). + +To host your preset config on Gitea: + +- Create a new repository on Gitea. Normally you'd call it `renovate-config` but you can use any name you want +- Add a `renovate.json` to this new repository containing the preset config. No other files are necessary +- In other repositories, reference it in an extends array like `"gitea>owner/name"`, e.g. `"gitea>rarkins/renovate-config"` + ## Local presets Renovate also supports local presets, e.g. presets that are hosted on the same platform as the target repository. This is especially helpful in self-hosted scenarios where public presets cannot be used. -Local presets are only supported on GitHub, GitLab and Bitbucket Server. +Local presets are only supported on GitHub, GitLab, Gitea and Bitbucket Server. Local presets are specified either by leaving out any prefix, e.g. `owner/name`, or explicitly by adding a `local>` prefix, e.g. `local>owner/name`. Renovate will determine the current platform and look up the preset from there. diff --git a/lib/config/presets/__snapshots__/index.spec.ts.snap b/lib/config/presets/__snapshots__/index.spec.ts.snap index ef54430677..22a81053c4 100644 --- a/lib/config/presets/__snapshots__/index.spec.ts.snap +++ b/lib/config/presets/__snapshots__/index.spec.ts.snap @@ -82,6 +82,15 @@ Object { } `; +exports[`config/presets parsePreset parses gitea 1`] = ` +Object { + "packageName": "some/repo", + "params": undefined, + "presetName": "default", + "presetSource": "gitea", +} +`; + exports[`config/presets parsePreset parses github 1`] = ` Object { "packageName": "some/repo", diff --git a/lib/config/presets/gitea/__snapshots__/index.spec.ts.snap b/lib/config/presets/gitea/__snapshots__/index.spec.ts.snap new file mode 100644 index 0000000000..80dcd962aa --- /dev/null +++ b/lib/config/presets/gitea/__snapshots__/index.spec.ts.snap @@ -0,0 +1,194 @@ +// Jest Snapshot v1, https://goo.gl/fbAQLP + +exports[`config/presets/gitea/index fetchJSONFile() returns JSON 1`] = ` +Object { + "from": "api", +} +`; + +exports[`config/presets/gitea/index fetchJSONFile() returns JSON 2`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/some-filename.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() should query preset within the file 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/somefile.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() should query subpreset 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/somefile.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() should return custom.json 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/custom.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() should return default.json 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/default.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() should throws not-found 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/somefile.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() throws if fails to parse 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/default.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() throws if no content 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/default.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPreset() tries default then renovate 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/default.json?", + }, + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/renovate.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPresetFromEndpoint() uses custom endpoint 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "api.gitea.example.org", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://api.gitea.example.org/repos/some/repo/contents/default.json?", + }, +] +`; + +exports[`config/presets/gitea/index getPresetFromEndpoint() uses default endpoint 1`] = ` +Array [ + Object { + "headers": Object { + "accept": "application/json", + "accept-encoding": "gzip, deflate", + "authorization": "token abc", + "host": "gitea.com", + "user-agent": "https://github.com/renovatebot/renovate", + }, + "method": "GET", + "url": "https://gitea.com/api/v1/repos/some/repo/contents/default.json?", + }, +] +`; diff --git a/lib/config/presets/gitea/index.spec.ts b/lib/config/presets/gitea/index.spec.ts new file mode 100644 index 0000000000..68b00de833 --- /dev/null +++ b/lib/config/presets/gitea/index.spec.ts @@ -0,0 +1,195 @@ +import * as httpMock from '../../../../test/httpMock'; +import { getName, mocked } from '../../../../test/util'; +import * as _hostRules from '../../../util/host-rules'; +import { setBaseUrl } from '../../../util/http/gitea'; +import { PRESET_NOT_FOUND } from '../util'; +import * as gitea from '.'; + +jest.mock('../../../util/host-rules'); + +const hostRules = mocked(_hostRules); + +const giteaApiHost = gitea.Endpoint; +const basePath = '/repos/some/repo/contents'; + +describe(getName(__filename), () => { + beforeEach(() => { + httpMock.setup(); + hostRules.find.mockReturnValue({ token: 'abc' }); + setBaseUrl(giteaApiHost); + }); + + afterEach(() => httpMock.reset()); + + describe('fetchJSONFile()', () => { + it('returns JSON', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/some-filename.json`) + .reply(200, { + content: Buffer.from('{"from":"api"}').toString('base64'), + }); + + const res = await gitea.fetchJSONFile( + 'some/repo', + 'some-filename.json', + giteaApiHost + ); + expect(res).toMatchSnapshot(); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + }); + + describe('getPreset()', () => { + it('tries default then renovate', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/default.json`) + .reply(404, {}) + .get(`${basePath}/renovate.json`) + .reply(200, {}); + + await expect( + gitea.getPreset({ packageName: 'some/repo' }) + ).rejects.toThrow(); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('throws if no content', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/default.json`) + .reply(200, {}); + + await expect( + gitea.getPreset({ packageName: 'some/repo' }) + ).rejects.toThrow('invalid preset JSON'); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('throws if fails to parse', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/default.json`) + .reply(200, { + content: Buffer.from('not json').toString('base64'), + }); + + await expect( + gitea.getPreset({ packageName: 'some/repo' }) + ).rejects.toThrow('invalid preset JSON'); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('should return default.json', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/default.json`) + .reply(200, { + content: Buffer.from('{"foo":"bar"}').toString('base64'), + }); + + const content = await gitea.getPreset({ packageName: 'some/repo' }); + expect(content).toEqual({ foo: 'bar' }); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('should query preset within the file', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/somefile.json`) + .reply(200, { + content: Buffer.from('{"somename":{"foo":"bar"}}').toString('base64'), + }); + const content = await gitea.getPreset({ + packageName: 'some/repo', + presetName: 'somefile/somename', + }); + expect(content).toEqual({ foo: 'bar' }); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('should query subpreset', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/somefile.json`) + .reply(200, { + content: Buffer.from( + '{"somename":{"somesubname":{"foo":"bar"}}}' + ).toString('base64'), + }); + + const content = await gitea.getPreset({ + packageName: 'some/repo', + presetName: 'somefile/somename/somesubname', + }); + expect(content).toEqual({ foo: 'bar' }); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('should return custom.json', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/custom.json`) + .reply(200, { + content: Buffer.from('{"foo":"bar"}').toString('base64'), + }); + const content = await gitea.getPreset({ + packageName: 'some/repo', + presetName: 'custom', + }); + expect(content).toEqual({ foo: 'bar' }); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('should throws not-found', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/somefile.json`) + .reply(200, { + content: Buffer.from('{}').toString('base64'), + }); + await expect( + gitea.getPreset({ + packageName: 'some/repo', + presetName: 'somefile/somename/somesubname', + }) + ).rejects.toThrow(PRESET_NOT_FOUND); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + }); + + describe('getPresetFromEndpoint()', () => { + it('uses default endpoint', async () => { + httpMock + .scope(giteaApiHost) + .get(`${basePath}/default.json`) + .reply(200, { + content: Buffer.from('{"from":"api"}').toString('base64'), + }); + expect( + await gitea.getPresetFromEndpoint('some/repo', 'default') + ).toEqual({ from: 'api' }); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + + it('uses custom endpoint', async () => { + httpMock + .scope('https://api.gitea.example.org') + .get(`${basePath}/default.json`) + .reply(200, { + content: Buffer.from('{"from":"api"}').toString('base64'), + }); + expect( + await gitea + .getPresetFromEndpoint( + 'some/repo', + 'default', + 'https://api.gitea.example.org' + ) + .catch(() => ({ from: 'api' })) + ).toEqual({ from: 'api' }); + expect(httpMock.getTrace()).toMatchSnapshot(); + }); + }); +}); diff --git a/lib/config/presets/gitea/index.ts b/lib/config/presets/gitea/index.ts new file mode 100644 index 0000000000..ff462b3f3e --- /dev/null +++ b/lib/config/presets/gitea/index.ts @@ -0,0 +1,58 @@ +import { logger } from '../../../logger'; +import { + RepoContents, + getRepoContents, +} from '../../../platform/gitea/gitea-helper'; +import { ExternalHostError } from '../../../types/errors/external-host-error'; +import { Preset, PresetConfig } from '../common'; +import { PRESET_DEP_NOT_FOUND, fetchPreset } from '../util'; + +export const Endpoint = 'https://gitea.com/api/v1/'; + +export async function fetchJSONFile( + repo: string, + fileName: string, + endpoint: string +): Promise<Preset> { + let res: RepoContents; + try { + res = await getRepoContents(repo, fileName, null, { baseUrl: endpoint }); + } catch (err) { + // istanbul ignore if: not testable with nock + if (err instanceof ExternalHostError) { + throw err; + } + logger.debug( + { statusCode: err.statusCode, repo, fileName }, + `Failed to retrieve ${fileName} from repo` + ); + throw new Error(PRESET_DEP_NOT_FOUND); + } + try { + const content = Buffer.from(res.content, 'base64').toString(); + const parsed = JSON.parse(content); + return parsed; + } catch (err) { + throw new Error('invalid preset JSON'); + } +} + +export function getPresetFromEndpoint( + pkgName: string, + filePreset: string, + endpoint = Endpoint +): Promise<Preset> { + return fetchPreset({ + pkgName, + filePreset, + endpoint, + fetch: fetchJSONFile, + }); +} + +export function getPreset({ + packageName: pkgName, + presetName = 'default', +}: PresetConfig): Promise<Preset> { + return getPresetFromEndpoint(pkgName, presetName, Endpoint); +} diff --git a/lib/config/presets/index.spec.ts b/lib/config/presets/index.spec.ts index 33082e4bbd..bffa7bdfd8 100644 --- a/lib/config/presets/index.spec.ts +++ b/lib/config/presets/index.spec.ts @@ -249,6 +249,9 @@ describe('config/presets', () => { it('parses gitlab', () => { expect(presets.parsePreset('gitlab>some/repo')).toMatchSnapshot(); }); + it('parses gitea', () => { + expect(presets.parsePreset('gitea>some/repo')).toMatchSnapshot(); + }); it('parses local', () => { expect(presets.parsePreset('local>some/repo')).toMatchSnapshot(); }); diff --git a/lib/config/presets/index.ts b/lib/config/presets/index.ts index 8f32a9acf5..6c5641b16e 100644 --- a/lib/config/presets/index.ts +++ b/lib/config/presets/index.ts @@ -11,6 +11,7 @@ import * as massage from '../massage'; import * as migration from '../migration'; import { mergeChildConfig } from '../utils'; import { PresetApi } from './common'; +import * as gitea from './gitea'; import * as github from './github'; import * as gitlab from './gitlab'; import * as internal from './internal'; @@ -21,6 +22,7 @@ const presetSources: Record<string, PresetApi> = { github, npm, gitlab, + gitea, local, internal, }; @@ -66,6 +68,9 @@ export function parsePreset(input: string): ParsedPreset { } else if (str.startsWith('gitlab>')) { presetSource = 'gitlab'; str = str.substring('gitlab>'.length); + } else if (str.startsWith('gitea>')) { + presetSource = 'gitea'; + str = str.substring('gitea>'.length); } else if (str.startsWith('local>')) { presetSource = 'local'; str = str.substring('local>'.length); diff --git a/lib/config/presets/local/__snapshots__/index.spec.ts.snap b/lib/config/presets/local/__snapshots__/index.spec.ts.snap index 9b45396622..c0887b2337 100644 --- a/lib/config/presets/local/__snapshots__/index.spec.ts.snap +++ b/lib/config/presets/local/__snapshots__/index.spec.ts.snap @@ -12,6 +12,18 @@ Array [ exports[`config/presets/local/index getPreset() forwards to custom bitbucket-server 2`] = `undefined`; +exports[`config/presets/local/index getPreset() forwards to custom gitea 1`] = ` +Array [ + Array [ + "some/repo", + "default", + "https://api.gitea.example.com", + ], +] +`; + +exports[`config/presets/local/index getPreset() forwards to custom gitea 2`] = `undefined`; + exports[`config/presets/local/index getPreset() forwards to custom github 1`] = ` Array [ Array [ @@ -44,6 +56,18 @@ Object { } `; +exports[`config/presets/local/index getPreset() forwards to gitea 1`] = ` +Array [ + Array [ + "some/repo", + "default", + undefined, + ], +] +`; + +exports[`config/presets/local/index getPreset() forwards to gitea 2`] = `undefined`; + exports[`config/presets/local/index getPreset() forwards to github 1`] = ` Array [ Array [ diff --git a/lib/config/presets/local/index.spec.ts b/lib/config/presets/local/index.spec.ts index 18abc6d280..16aecc2c3f 100644 --- a/lib/config/presets/local/index.spec.ts +++ b/lib/config/presets/local/index.spec.ts @@ -1,15 +1,18 @@ import { getName, mocked } from '../../../../test/util'; import * as _bitbucketServer from '../bitbucket-server'; +import * as _gitea from '../gitea'; import * as _github from '../github'; import * as _gitlab from '../gitlab'; import * as local from '.'; jest.mock('../gitlab'); jest.mock('../github'); +jest.mock('../gitea'); jest.mock('../bitbucket-server'); const gitlab = mocked(_gitlab); const github = mocked(_github); +const gitea = mocked(_gitea); const bitbucketServer = mocked(_bitbucketServer); describe(getName(__filename), () => { @@ -88,6 +91,29 @@ describe(getName(__filename), () => { expect(content).toMatchSnapshot(); }); + it('forwards to gitea', async () => { + const content = await local.getPreset({ + packageName: 'some/repo', + baseConfig: { + platform: 'gitea', + }, + }); + expect(gitea.getPresetFromEndpoint.mock.calls).toMatchSnapshot(); + expect(content).toMatchSnapshot(); + }); + it('forwards to custom gitea', async () => { + const content = await local.getPreset({ + packageName: 'some/repo', + presetName: 'default', + baseConfig: { + platform: 'gitea', + endpoint: 'https://api.gitea.example.com', + }, + }); + expect(gitea.getPresetFromEndpoint.mock.calls).toMatchSnapshot(); + expect(content).toMatchSnapshot(); + }); + it('forwards to custom bitbucket-server', async () => { const content = await local.getPreset({ packageName: 'some/repo', diff --git a/lib/config/presets/local/index.ts b/lib/config/presets/local/index.ts index 93421af71e..6605d007d5 100644 --- a/lib/config/presets/local/index.ts +++ b/lib/config/presets/local/index.ts @@ -1,10 +1,12 @@ import { PLATFORM_TYPE_BITBUCKET_SERVER, + PLATFORM_TYPE_GITEA, PLATFORM_TYPE_GITHUB, PLATFORM_TYPE_GITLAB, } from '../../../constants/platforms'; import * as bitbucketServer from '../bitbucket-server'; import { Preset, PresetConfig } from '../common'; +import * as gitea from '../gitea'; import * as github from '../github'; import * as gitlab from '../gitlab'; @@ -28,6 +30,8 @@ export function getPreset({ presetName, endpoint ); + case PLATFORM_TYPE_GITEA: + return gitea.getPresetFromEndpoint(pkgName, presetName, endpoint); default: throw new Error( `Unsupported platform '${baseConfig.platform}' for local preset.` diff --git a/lib/util/http/gitea.ts b/lib/util/http/gitea.ts index 6078596c3c..a549fd5ec9 100644 --- a/lib/util/http/gitea.ts +++ b/lib/util/http/gitea.ts @@ -23,8 +23,8 @@ function getPaginationContainer(body: any): any[] { return null; } -function resolveUrl(path: string): URL { - const resolvedUrlString = url.resolve(baseUrl, path); +function resolveUrl(path: string, base: string): URL { + const resolvedUrlString = url.resolve(base, path); return new url.URL(resolvedUrlString); } @@ -37,7 +37,7 @@ export class GiteaHttp extends Http<GiteaHttpOptions, GiteaHttpOptions> { path: string, options?: InternalHttpOptions & GiteaHttpOptions ): Promise<HttpResponse<T> | null> { - const resolvedUrl = resolveUrl(path); + const resolvedUrl = resolveUrl(path, options.baseUrl ?? baseUrl); const opts = { baseUrl, ...options, -- GitLab