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: add preflight method to ManagerAPI #31112

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions docs/development/adding-a-package-manager.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ The manager's `index.ts` file supports the following values or functions:
| `extractAllPackageFiles` | yes | yes |
| `getRangeStrategy` | yes | |
| `categories` | yes | |
| `preflight` | yes | yes |
| `supportsLockFileMaintenance` | yes | |
| `updateArtifacts` | yes | yes |
| `updateDependency` | yes | |
Expand Down Expand Up @@ -82,6 +83,16 @@ The `npm` manager uses the `getRangeStrategy` function to pin `devDependencies`

If left undefined, then a default `getRangeStrategy` will be used that always returns "replace".

### `categories` (optional)

Use `categories` to define the categories of dependencies that the manager supports.
These usually are describing the purpose of the managed dependencies like `iac` for Infrastructure as Code or ecosystems like `js` for Javascript.

### `preflight` (optional)

Use `preflight` to modify Renovates config based on the repository content.
For example, if a repository contains files with `.tofu` ending, then change the `filematch` and change the registry.

### `supportsLockFileMaintenance` (optional)

Set to `true` if this package manager needs to update lock files in addition to package files.
Expand Down
3 changes: 3 additions & 0 deletions lib/modules/manager/types.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import type { ReleaseType } from 'semver';
import type {
MatchStringsStrategy,
RenovateConfig,
UpdateType,
UserEnv,
ValidationMessage,
Expand Down Expand Up @@ -285,6 +286,8 @@ export interface ManagerApi extends ModuleApi {
updateLockedDependency?(
config: UpdateLockedConfig,
): Result<UpdateLockedResult>;

preflight?(config: RenovateConfig): Result<RenovateConfig>;
}

// TODO: name and properties used by npm manager
Expand Down
75 changes: 74 additions & 1 deletion lib/workers/repository/extract/index.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ import { mocked, partial, scm } from '../../../../test/util';
import { getConfig } from '../../../config/defaults';
import type { RenovateConfig } from '../../../config/types';
import { logger } from '../../../logger';
import * as managers from '../../../modules/manager';
import type { PackageFile } from '../../../modules/manager/types';
import * as _managerFiles from './manager-files';
import { extractAllDependencies } from '.';
import { applyPreFlights, extractAllDependencies } from '.';

jest.mock('./manager-files');
jest.mock('../../../util/git');
Expand Down Expand Up @@ -68,4 +69,76 @@ describe('workers/repository/extract/index', () => {
expect(Object.keys(res.packageFiles)).toContain('regex');
});
});

describe('applyPreFlights()', () => {
const getFunction = jest.spyOn(managers, 'get');
const baseConfig: RenovateConfig = {
foo: 'bar',
};

it('should return same config for unknown manager', async () => {
await expect(applyPreFlights(baseConfig, ['test'])).resolves.toEqual({
foo: 'bar',
});
});

it('should return modified config for manager', async () => {
getFunction.mockReturnValueOnce((config: RenovateConfig) => {
return {
...config,
foo: 'foo',
};
});

await expect(applyPreFlights(baseConfig, ['test'])).resolves.toEqual({
foo: 'foo',
});
});

it('should return modified config for multiple managers', async () => {
getFunction.mockReturnValueOnce((config: RenovateConfig) => {
return {
...config,
foo: 'foo',
};
});
getFunction.mockReturnValueOnce((config: RenovateConfig) => {
return {
...config,
lip: 'sum',
foo: 'bar',
};
});

await expect(
applyPreFlights(baseConfig, ['test', 'another-manager']),
).resolves.toEqual({
foo: 'bar',
lip: 'sum',
});
});

it('should return modified config for async preflights managers', async () => {
getFunction.mockReturnValueOnce((config: RenovateConfig) => {
return {
...config,
foo: 'foo',
};
});
getFunction.mockReturnValueOnce((config: RenovateConfig) => {
return Promise.resolve({
...config,
lip: 'sum',
foo: 'bar',
});
});

await expect(
applyPreFlights(baseConfig, ['test', 'another-manager']),
).resolves.toEqual({
foo: 'bar',
lip: 'sum',
});
});
});
});
36 changes: 33 additions & 3 deletions lib/workers/repository/extract/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import is from '@sindresorhus/is';
import { getManagerConfig, mergeChildConfig } from '../../../config';
import type { ManagerConfig, RenovateConfig } from '../../../config/types';
import { logger } from '../../../logger';
import { getEnabledManagersList, hashMap } from '../../../modules/manager';
import { get, getEnabledManagersList, hashMap } from '../../../modules/manager';
import { isCustomManager } from '../../../modules/manager/custom';
import { scm } from '../../../modules/platform/scm';
import type { ExtractResult, WorkerExtractConfig } from '../../types';
Expand All @@ -11,9 +11,13 @@ import { getManagerPackageFiles } from './manager-files';
import { processSupersedesManagers } from './supersedes';

export async function extractAllDependencies(
config: RenovateConfig,
initConfig: RenovateConfig,
): Promise<ExtractResult> {
const managerList = getEnabledManagersList(config.enabledManagers);
const managerList = getEnabledManagersList(initConfig.enabledManagers);

// process all preflight checks
const config = await applyPreFlights(initConfig, managerList);

const extractList: WorkerExtractConfig[] = [];
const fileList = await scm.getFileList();

Expand Down Expand Up @@ -97,3 +101,29 @@ export async function extractAllDependencies(

return extractResult;
}

export async function applyPreFlights(
config: RenovateConfig,
managerList: string[],
): Promise<RenovateConfig> {
let result = config;
for (const manager of managerList) {
const preflight = get(manager, 'preflight');
if (!preflight) {
continue;
}

logger.debug({ manager }, `Running preflight`);
logger.trace(
{ manager, config: result },
`Config before running preflight for manager: '${manager}'`,
);
result = await preflight(result);
logger.trace(
{ manager, config: result },
`Config after running preflight for '${manager}'`,
);
}

return result;
}