feat(self-hosted): autodiscoverRepoSort and autodiscoverRepoOrder (#28738)

Co-authored-by: Rhys Arkins <rhys@arkins.net>
This commit is contained in:
RahulGautamSingh 2024-05-07 00:01:01 +05:45 committed by GitHub
parent 3de9ac7e10
commit 10a4a8bb26
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
13 changed files with 124 additions and 58 deletions

View file

@ -233,6 +233,18 @@ This feature is useful for users who want Renovate to only work on repositories
The `autodiscoverProjects` config option takes an array of minimatch-compatible globs or RE2-compatible regex strings.
For more details on this syntax see Renovate's [string pattern matching documentation](./string-pattern-matching.md).
## autodiscoverRepoOrder
The order method for autodiscover server side repository search.
> If multiple `autodiscoverTopics` are used resulting order will be per topic not global.
## autodiscoverRepoSort
The sort method for autodiscover server side repository search.
> If multiple `autodiscoverTopics` are used resulting order will be per topic not global.
## autodiscoverTopics
Some platforms allow you to add tags, or topics, to repositories and retrieve repository lists by specifying those

View file

@ -32,43 +32,6 @@ Skipping the check will speed things up, but may result in versions being return
If set to any value, Renovate will always paginate requests to GitHub fully, instead of stopping after 10 pages.
## `RENOVATE_X_AUTODISCOVER_REPO_ORDER`
<!-- prettier-ignore -->
!!! note
For the Forgejo and Gitea platform only.
The order method for autodiscover server side repository search.
> If multiple `autodiscoverTopics` are used resulting order will be per topic not global.
Allowed values:
- `asc`
- `desc`
Default value: `asc`.
## `RENOVATE_X_AUTODISCOVER_REPO_SORT`
<!-- prettier-ignore -->
!!! note
For the Forgejo and Gitea platform only.
The sort method for autodiscover server side repository search.
> If multiple `autodiscoverTopics` are used resulting order will be per topic not global.
Allowed values:
- `alpha`
- `created`
- `updated`
- `size`
- `id`
Default value: `alpha`.
## `RENOVATE_X_DELETE_CONFIG_FILE`
If `true` Renovate tries to delete the self-hosted config file after reading it.

View file

@ -33,6 +33,8 @@ export class GlobalConfig {
'platform',
'endpoint',
'httpCacheTtlDays',
'autodiscoverRepoSort',
'autodiscoverRepoOrder',
'userAgent',
];

View file

@ -22,6 +22,26 @@ const options: RenovateOptions[] = [
globalOnly: true,
patternMatch: true,
},
{
name: 'autodiscoverRepoOrder',
description:
'The order method for autodiscover server side repository search.',
type: 'string',
default: null,
globalOnly: true,
allowedValues: ['asc', 'desc'],
supportedPlatforms: ['gitea'],
},
{
name: 'autodiscoverRepoSort',
description:
'The sort method for autodiscover server side repository search.',
type: 'string',
default: null,
globalOnly: true,
allowedValues: ['alpha', 'created', 'updated', 'size', 'id'],
supportedPlatforms: ['gitea'],
},
{
name: 'allowedEnv',
description:

View file

@ -2,6 +2,7 @@ import type { LogLevel } from 'bunyan';
import type { PlatformId } from '../constants';
import type { LogLevelRemap } from '../logger/types';
import type { CustomManager } from '../modules/manager/custom/types';
import type { RepoSortMethod, SortMethod } from '../modules/platform/types';
import type { HostRule } from '../types';
import type { GitNoVerifyOption } from '../util/git/types';
import type { MergeConfidence } from '../util/merge-confidence/types';
@ -159,6 +160,8 @@ export interface RepoGlobalConfig {
privateKey?: string;
privateKeyOld?: string;
httpCacheTtlDays?: number;
autodiscoverRepoSort?: RepoSortMethod;
autodiscoverRepoOrder?: SortMethod;
userAgent?: string;
}

View file

@ -224,9 +224,6 @@ describe('modules/platform/gitea/index', () => {
hostRules.clear();
setBaseUrl('https://gitea.renovatebot.com/');
delete process.env.RENOVATE_X_AUTODISCOVER_REPO_SORT;
delete process.env.RENOVATE_X_AUTODISCOVER_REPO_ORDER;
});
async function initFakePlatform(
@ -421,8 +418,6 @@ describe('modules/platform/gitea/index', () => {
});
it('Sorts repos', async () => {
process.env.RENOVATE_X_AUTODISCOVER_REPO_SORT = 'updated';
process.env.RENOVATE_X_AUTODISCOVER_REPO_ORDER = 'desc';
const scope = httpMock
.scope('https://gitea.com/api/v1')
.get('/repos/search')
@ -438,7 +433,10 @@ describe('modules/platform/gitea/index', () => {
});
await initFakePlatform(scope);
const repos = await gitea.getRepos();
const repos = await gitea.getRepos({
sort: 'updated',
order: 'desc',
});
expect(repos).toEqual(['a/b', 'c/d']);
});
});

View file

@ -34,6 +34,8 @@ import type {
Pr,
RepoParams,
RepoResult,
RepoSortMethod,
SortMethod,
UpdatePrConfig,
} from '../types';
import { repoFingerprint } from '../util';
@ -49,8 +51,6 @@ import type {
PRMergeMethod,
PRUpdateParams,
Repo,
RepoSortMethod,
SortMethod,
} from './types';
import {
DRAFT_PREFIX,
@ -159,7 +159,17 @@ async function lookupLabelByName(name: string): Promise<number | null> {
return labelList.find((l) => l.name === name)?.id ?? null;
}
async function fetchRepositories(topic?: string): Promise<string[]> {
interface FetchRepositoriesArgs {
topic?: string;
sort?: RepoSortMethod;
order?: SortMethod;
}
async function fetchRepositories({
topic,
sort,
order,
}: FetchRepositoriesArgs): Promise<string[]> {
const repos = await helper.searchRepos({
uid: botUserID,
archived: false,
@ -167,11 +177,11 @@ async function fetchRepositories(topic?: string): Promise<string[]> {
topic: true,
q: topic,
}),
...(process.env.RENOVATE_X_AUTODISCOVER_REPO_SORT && {
sort: process.env.RENOVATE_X_AUTODISCOVER_REPO_SORT as RepoSortMethod,
...(sort && {
sort,
}),
...(process.env.RENOVATE_X_AUTODISCOVER_REPO_ORDER && {
order: process.env.RENOVATE_X_AUTODISCOVER_REPO_ORDER as SortMethod,
...(order && {
order,
}),
});
return repos.filter(usableRepo).map((r) => r.full_name);
@ -330,7 +340,16 @@ const platform: Platform = {
try {
if (config?.topics) {
logger.debug({ topics: config.topics }, 'Auto-discovering by topics');
const repos = await map(config.topics, fetchRepositories);
const fetchRepoArgs: FetchRepositoriesArgs[] = config.topics.map(
(topic) => {
return {
topic,
sort: config.sort,
order: config.order,
};
},
);
const repos = await map(fetchRepoArgs, fetchRepositories);
return deduplicateArray(repos.flat());
} else if (config?.namespaces) {
logger.debug(
@ -348,7 +367,10 @@ const platform: Platform = {
);
return deduplicateArray(repos.flat());
} else {
return await fetchRepositories();
return await fetchRepositories({
sort: config?.sort,
order: config?.order,
});
}
} catch (err) {
logger.error({ err }, 'Gitea getRepos() error');

View file

@ -48,5 +48,5 @@ Repositories are ignored when one of the following conditions is met:
- Pull requests are disabled for that repository
You can change the default server-side sort method and order for autodiscover API.
Set those via [`RENOVATE_X_AUTODISCOVER_REPO_SORT`](../../../self-hosted-experimental.md#renovate_x_autodiscover_repo_sort) and [`RENOVATE_X_AUTODISCOVER_REPO_ORDER`](../../../self-hosted-experimental.md#renovate_x_autodiscover_repo_order).
Set those via [`autodiscoverRepoSort`](../../../self-hosted-configuration.md#autodiscoverRepoSort) and [`autodiscoverRepoOrder`](../../../self-hosted-configuration.md#autodiscoverRepoOrder).
Read the [Gitea swagger docs](https://try.gitea.io/api/swagger#/repository/repoSearch) for more details.

View file

@ -1,5 +1,5 @@
import type { LongCommitSha } from '../../../util/git/types';
import type { Pr } from '../types';
import type { Pr, RepoSortMethod, SortMethod } from '../types';
export interface PrReviewersParams {
reviewers?: string[];
@ -147,10 +147,6 @@ export interface CombinedCommitStatus {
statuses: CommitStatus[];
}
export type RepoSortMethod = 'alpha' | 'created' | 'updated' | 'size' | 'id';
export type SortMethod = 'asc' | 'desc';
export interface RepoSearchParams {
uid?: number;
archived?: boolean;

View file

@ -201,8 +201,19 @@ export type EnsureCommentRemovalConfig =
export type EnsureIssueResult = 'updated' | 'created';
export type RepoSortMethod =
| 'alpha'
| 'created'
| 'updated'
| 'size'
| 'id'
| null;
export type SortMethod = 'asc' | 'desc' | null;
export interface AutodiscoverConfig {
topics?: string[];
sort?: RepoSortMethod;
order?: SortMethod;
includeMirrors?: boolean;
namespaces?: string[];
projects?: string[];

View file

@ -38,6 +38,8 @@ export async function autodiscoverRepositories(
// Autodiscover list of repositories
let discovered = await platform.getRepos({
topics: config.autodiscoverTopics,
sort: config.autodiscoverRepoSort,
order: config.autodiscoverRepoOrder,
includeMirrors: config.includeMirrors,
namespaces: config.autodiscoverNamespaces,
projects: config.autodiscoverProjects,

View file

@ -267,6 +267,18 @@ describe('workers/global/config/parse/env', () => {
expect(config.token).toBe('a');
});
it('massages converted experimental env vars', async () => {
const envParam: NodeJS.ProcessEnv = {
RENOVATE_X_AUTODISCOVER_REPO_SORT: 'alpha',
RENOVATE_X_DOCKER_MAX_PAGES: '10',
RENOVATE_AUTODISCOVER_REPO_ORDER: 'desc',
};
const config = await env.getConfig(envParam);
expect(config.autodiscoverRepoSort).toBe('alpha');
expect(config.autodiscoverRepoOrder).toBe('desc');
expect(config.dockerMaxPages).toBeUndefined();
});
describe('RENOVATE_CONFIG tests', () => {
let processExit: jest.SpyInstance<never, [code?: number]>;

View file

@ -83,6 +83,30 @@ function massageEnvKeyValues(env: NodeJS.ProcessEnv): NodeJS.ProcessEnv {
return result;
}
const convertedExperimentalEnvVars = [
'RENOVATE_X_AUTODISCOVER_REPO_SORT',
'RENOVATE_X_AUTODISCOVER_REPO_ORDER',
];
/**
* Massages the experimental env vars which have been converted to config options
*
* e.g. RENOVATE_X_AUTODISCOVER_REPO_SORT -> RENOVATE_AUTODISCOVER_REPO_SORT
*/
function massageConvertedExperimentalVars(
env: NodeJS.ProcessEnv,
): NodeJS.ProcessEnv {
const result = { ...env };
for (const key of convertedExperimentalEnvVars) {
if (env[key] !== undefined) {
const newKey = key.replace('RENOVATE_X_', 'RENOVATE_');
result[newKey] = env[key];
delete result[key];
}
}
return result;
}
export async function getConfig(
inputEnv: NodeJS.ProcessEnv,
): Promise<AllConfig> {
@ -91,6 +115,7 @@ export async function getConfig(
env = renameEnvKeys(env);
// massage the values of migrated configuration keys
env = massageEnvKeyValues(env);
env = massageConvertedExperimentalVars(env);
const options = getOptions();