diff --git a/docs/development/shareable-configs.md b/docs/development/shareable-configs.md index 9b1058e5961e5ed64a2a1f0c28c56e4850ee14d7..906d0b0b4b4c9d100917a7a3cf7932d1500e3a06 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 701f12f10e60fd70b4e63b066a4f8d097361b26c..d67a7c08e869dcb9f9c000425b8416261de6d573 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 ef54430677792db2bb498836ae58ad534becd1fa..22a81053c4bd06e95b5a5b23cee014e1acfa1d39 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 0000000000000000000000000000000000000000..80dcd962aaa98422eff43c049703a0d9661103b9 --- /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 0000000000000000000000000000000000000000..68b00de833ee374eeaec7a545e37d252a92b371b --- /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 0000000000000000000000000000000000000000..ff462b3f3eb01de29e2bb103933d73343d5f341f --- /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 33082e4bbde87ea96aab1a7e48bf713c7dba154a..bffa7bdfd80ad9d4e568d82babba4156afe91712 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 8f32a9acf5d8f6734c836afc0a8cbfd145a4de24..6c5641b16e8f517a0dfcc4fde42d11d83ce8cff1 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 9b4539662224f922bc242647811f98c1ea68ae04..c0887b233783218fb837ac2aba3b1b5ad73216c9 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 18abc6d2809831ac7164f08db2047149e949b674..16aecc2c3fb6925572fa79878dbe37e1d5df5a20 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 93421af71ee3faf7ca76ff21bbcf3664a2adbf9b..6605d007d59828a7fa4c0999697cf7dd107aa591 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 6078596c3cba259670a556ffb61b6156cba6049c..a549fd5ec90e94607a3a5031dcfc9c636eb3f824 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,