mirror of
https://github.com/renovatebot/renovate.git
synced 2026-10-31 17:51:49 +00:00
5b1749983c
As noted in #43761, we had recently set `CI=true` for the Renovate and Containerbase orgs on Mend-hosted apps due to a pnpm v11 requirement: ERR_PNPM_ABORTED_REMOVE_MODULES_DIR_NO_TTY Aborted removal of modules directory due to no TTY If you are running pnpm in CI, set the CI environment variable to "true", or set "confirmModulesPurge" to "false". Similarly in #43606, it was noted that we should do this for `mise lock` to mark the workspace as "trusted". Although we went with a different situation, there will be cases where this is useful for tools being executed, for instance when we invoke `yarn`. We also make sure to keep our documentation up-to-date as we add to the specific overrides. With help from Claude Sonnet and Opus to: - perform some of the mechanical updates as part of this change - ensure that the Docker sidecar always has `hardcodedProcessEnv` passed into it - catch a needed change to `exposeAllEnv` handling Co-authored-by: Claude Opus 5 <jamie.tanna+claude-code@mend.io> Co-authored-by: Claude Sonnet 5 <jamie.tanna+claude-code@mend.io>
383 lines
12 KiB
TypeScript
383 lines
12 KiB
TypeScript
import upath from 'upath';
|
|
import { mockExecAll } from '~test/exec-util.ts';
|
|
import { fs, partial } from '~test/util.ts';
|
|
import { GlobalConfig } from '../../../../config/global.ts';
|
|
import type {
|
|
InternalGlobalConfigOptions,
|
|
RepoGlobalConfig,
|
|
} from '../../../../config/types.ts';
|
|
import { TEMPORARY_ERROR } from '../../../../constants/error-messages.ts';
|
|
import { logger } from '../../../../logger/index.ts';
|
|
import * as hostRules from '../../../../util/host-rules.ts';
|
|
import { getPkgReleases as _getPkgReleases } from '../../../datasource/index.ts';
|
|
import type { UpdateArtifact, UpdateArtifactsConfig } from '../../types.ts';
|
|
import { parsePyProject } from '../extract.ts';
|
|
import { depTypes } from '../utils.ts';
|
|
import { PdmProcessor } from './pdm.ts';
|
|
|
|
vi.mock('../../../../util/fs/index.ts');
|
|
vi.mock('../../../datasource/index.ts');
|
|
|
|
const getPkgReleases = vi.mocked(_getPkgReleases);
|
|
|
|
const config: UpdateArtifactsConfig = {};
|
|
const adminConfig: RepoGlobalConfig & InternalGlobalConfigOptions = {
|
|
localDir: upath.join('/tmp/github/some/repo'),
|
|
cacheDir: upath.join('/tmp/cache'),
|
|
containerbaseDir: upath.join('/tmp/cache/containerbase'),
|
|
binarySource: 'global',
|
|
};
|
|
|
|
const processor = new PdmProcessor();
|
|
|
|
describe('modules/manager/pep621/processors/pdm', () => {
|
|
describe('updateArtifacts()', () => {
|
|
it('throws TEMPORARY_ERROR', async () => {
|
|
fs.readLocalFile.mockRejectedValueOnce(new Error(TEMPORARY_ERROR));
|
|
const result = processor.updateArtifacts(
|
|
partial<UpdateArtifact>({ config: {} }),
|
|
partial(),
|
|
);
|
|
await expect(result).rejects.toThrow(TEMPORARY_ERROR);
|
|
});
|
|
|
|
it('return null if there is no lock file', async () => {
|
|
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
|
|
const updatedDeps = [{ packageName: 'dep1' }];
|
|
const result = await processor.updateArtifacts(
|
|
{
|
|
packageFileName: 'pyproject.toml',
|
|
newPackageFileContent: '',
|
|
config,
|
|
updatedDeps,
|
|
},
|
|
parsePyProject('')!,
|
|
);
|
|
expect(result).toBeNull();
|
|
});
|
|
|
|
it('return null if the lock file is unchanged', async () => {
|
|
const execSnapshots = mockExecAll();
|
|
GlobalConfig.set({
|
|
...adminConfig,
|
|
binarySource: 'docker',
|
|
dockerSidecarImage: 'ghcr.io/renovatebot/base-image',
|
|
});
|
|
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
|
|
fs.readLocalFile.mockResolvedValueOnce('test content');
|
|
fs.readLocalFile.mockResolvedValueOnce('test content');
|
|
// python
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: '3.11.1' }, { version: '3.11.2' }],
|
|
});
|
|
// pdm
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
|
|
});
|
|
|
|
const updatedDeps = [{ packageName: 'dep1' }];
|
|
const result = await processor.updateArtifacts(
|
|
{
|
|
packageFileName: 'pyproject.toml',
|
|
newPackageFileContent: '',
|
|
config: { constraints: {} },
|
|
updatedDeps,
|
|
},
|
|
parsePyProject('')!,
|
|
);
|
|
expect(result).toBeNull();
|
|
expect(execSnapshots).toMatchObject([
|
|
{
|
|
cmd: 'docker pull ghcr.io/renovatebot/base-image',
|
|
},
|
|
{
|
|
cmd: 'docker ps --filter name=renovate_sidecar -aq',
|
|
},
|
|
{
|
|
cmd:
|
|
'docker run --rm --name=renovate_sidecar --label=renovate_child ' +
|
|
'-v "/tmp/github/some/repo":"/tmp/github/some/repo" ' +
|
|
'-v "/tmp/cache":"/tmp/cache" ' +
|
|
'-e CI ' +
|
|
'-e CONTAINERBASE_CACHE_DIR ' +
|
|
'-w "/tmp/github/some/repo" ' +
|
|
'ghcr.io/renovatebot/base-image ' +
|
|
"bash -l -c '" +
|
|
'install-tool python 3.11.2 ' +
|
|
'&& ' +
|
|
'install-tool pdm v2.5.0 ' +
|
|
'&& ' +
|
|
'pdm update --no-sync --update-eager dep1' +
|
|
"'",
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('returns artifact error', async () => {
|
|
const execSnapshots = mockExecAll();
|
|
GlobalConfig.set({ ...adminConfig, binarySource: 'docker' });
|
|
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
|
|
fs.readLocalFile.mockImplementationOnce(() => {
|
|
throw new Error('test error');
|
|
});
|
|
|
|
const updatedDeps = [{ packageName: 'dep1' }];
|
|
const result = await processor.updateArtifacts(
|
|
{
|
|
packageFileName: 'pyproject.toml',
|
|
newPackageFileContent: '',
|
|
config: {},
|
|
updatedDeps,
|
|
},
|
|
parsePyProject('')!,
|
|
);
|
|
expect(result).toEqual([
|
|
{ artifactError: { fileName: 'pdm.lock', stderr: 'test error' } },
|
|
]);
|
|
expect(execSnapshots).toEqual([]);
|
|
});
|
|
|
|
it('return update dep update', async () => {
|
|
const execSnapshots = mockExecAll();
|
|
GlobalConfig.set(adminConfig);
|
|
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
|
|
fs.readLocalFile.mockResolvedValueOnce('test content');
|
|
fs.readLocalFile.mockResolvedValueOnce('changed test content');
|
|
// python
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: '3.11.1' }, { version: '3.11.2' }],
|
|
});
|
|
// pdm
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
|
|
});
|
|
|
|
const updatedDeps = [
|
|
{
|
|
packageName: 'dep1',
|
|
depType: depTypes.dependencies,
|
|
},
|
|
{ packageName: 'dep2', depType: depTypes.dependencies },
|
|
{
|
|
packageName: 'dep3',
|
|
managerData: { depGroup: 'group1' },
|
|
depType: depTypes.optionalDependencies,
|
|
},
|
|
{
|
|
packageName: 'dep4',
|
|
depType: depTypes.optionalDependencies,
|
|
managerData: { depGroup: 'group1' },
|
|
},
|
|
{
|
|
packageName: 'dep5',
|
|
depType: depTypes.pdmDevDependencies,
|
|
managerData: { depGroup: 'group2' },
|
|
},
|
|
{
|
|
packageName: 'dep6',
|
|
depType: depTypes.pdmDevDependencies,
|
|
managerData: { depGroup: 'group2' },
|
|
},
|
|
{
|
|
packageName: 'dep7',
|
|
depType: depTypes.pdmDevDependencies,
|
|
managerData: { depGroup: 'group3' },
|
|
},
|
|
{
|
|
packageName: 'dep8',
|
|
depType: depTypes.pdmDevDependencies,
|
|
managerData: { depGroup: 'group3' },
|
|
},
|
|
{ packageName: 'dep9', depType: depTypes.buildSystemRequires },
|
|
{
|
|
packageName: 'dep10',
|
|
depType: depTypes.dependencyGroups,
|
|
managerData: { depGroup: 'dev' },
|
|
},
|
|
];
|
|
const result = await processor.updateArtifacts(
|
|
{
|
|
packageFileName: 'pyproject.toml',
|
|
newPackageFileContent: '',
|
|
config: {},
|
|
updatedDeps,
|
|
},
|
|
parsePyProject('')!,
|
|
);
|
|
expect(result).toEqual([
|
|
{
|
|
file: {
|
|
contents: 'changed test content',
|
|
path: 'pdm.lock',
|
|
type: 'addition',
|
|
},
|
|
},
|
|
]);
|
|
expect(execSnapshots).toMatchObject([
|
|
{
|
|
cmd: 'pdm update --no-sync --update-eager dep1 dep2',
|
|
},
|
|
{
|
|
cmd: 'pdm update --no-sync --update-eager -G group1 dep3 dep4',
|
|
},
|
|
{
|
|
cmd: 'pdm update --no-sync --update-eager -dG group2 dep5 dep6',
|
|
},
|
|
{
|
|
cmd: 'pdm update --no-sync --update-eager -dG group3 dep7 dep8',
|
|
},
|
|
{
|
|
cmd: 'pdm update --no-sync --update-eager -dG dev dep10',
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('discard dependencies if the devGroup is missing', async () => {
|
|
const execSnapshots = mockExecAll();
|
|
GlobalConfig.set(adminConfig);
|
|
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
|
|
fs.readLocalFile.mockResolvedValueOnce('test content');
|
|
fs.readLocalFile.mockResolvedValueOnce('test content');
|
|
// python
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: '3.11.1' }, { version: '3.11.2' }],
|
|
});
|
|
// pdm
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
|
|
});
|
|
|
|
const updatedDeps = [
|
|
{
|
|
packageName: 'dep3',
|
|
depType: depTypes.optionalDependencies,
|
|
},
|
|
{
|
|
packageName: 'dep5',
|
|
depType: depTypes.pdmDevDependencies,
|
|
},
|
|
{
|
|
packageName: 'dep10',
|
|
depType: depTypes.dependencyGroups,
|
|
},
|
|
];
|
|
const result = await processor.updateArtifacts(
|
|
{
|
|
packageFileName: 'pyproject.toml',
|
|
newPackageFileContent: '',
|
|
config: {},
|
|
updatedDeps,
|
|
},
|
|
parsePyProject('')!,
|
|
);
|
|
expect(result).toBeNull();
|
|
expect(execSnapshots).toEqual([]);
|
|
expect(logger.once.warn).toHaveBeenCalledTimes(3);
|
|
});
|
|
|
|
it('return update on lockfileMaintenance', async () => {
|
|
const execSnapshots = mockExecAll();
|
|
GlobalConfig.set(adminConfig);
|
|
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
|
|
fs.readLocalFile.mockResolvedValueOnce('test content');
|
|
fs.readLocalFile.mockResolvedValueOnce('changed test content');
|
|
// python
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: '3.11.1' }, { version: '3.11.2' }],
|
|
});
|
|
// pdm
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
|
|
});
|
|
|
|
const result = await processor.updateArtifacts(
|
|
{
|
|
packageFileName: 'folder/pyproject.toml',
|
|
newPackageFileContent: '',
|
|
config: {
|
|
isLockFileMaintenance: true,
|
|
},
|
|
updatedDeps: [],
|
|
},
|
|
parsePyProject('')!,
|
|
);
|
|
expect(result).toEqual([
|
|
{
|
|
file: {
|
|
contents: 'changed test content',
|
|
path: 'pdm.lock',
|
|
type: 'addition',
|
|
},
|
|
},
|
|
]);
|
|
expect(execSnapshots).toMatchObject([
|
|
{
|
|
cmd: 'pdm update --no-sync --update-eager',
|
|
options: {
|
|
cwd: '/tmp/github/some/repo/folder',
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
|
|
it('sets Git environment variables', async () => {
|
|
hostRules.add({
|
|
matchHost: 'https://example.com',
|
|
username: 'user',
|
|
password: 'pass',
|
|
});
|
|
const execSnapshots = mockExecAll();
|
|
GlobalConfig.set(adminConfig);
|
|
fs.getSiblingFileName.mockReturnValueOnce('pdm.lock');
|
|
fs.readLocalFile.mockResolvedValueOnce('test content');
|
|
fs.readLocalFile.mockResolvedValueOnce('changed test content');
|
|
// python
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: '3.11.1' }, { version: '3.11.2' }],
|
|
});
|
|
// pdm
|
|
getPkgReleases.mockResolvedValueOnce({
|
|
releases: [{ version: 'v2.6.1' }, { version: 'v2.5.0' }],
|
|
});
|
|
|
|
const result = await processor.updateArtifacts(
|
|
{
|
|
packageFileName: 'folder/pyproject.toml',
|
|
newPackageFileContent: '',
|
|
config: {
|
|
isLockFileMaintenance: true,
|
|
},
|
|
updatedDeps: [],
|
|
},
|
|
parsePyProject('')!,
|
|
);
|
|
expect(result).toEqual([
|
|
{
|
|
file: {
|
|
contents: 'changed test content',
|
|
path: 'pdm.lock',
|
|
type: 'addition',
|
|
},
|
|
},
|
|
]);
|
|
expect(execSnapshots).toMatchObject([
|
|
{
|
|
cmd: 'pdm update --no-sync --update-eager',
|
|
options: {
|
|
cwd: '/tmp/github/some/repo/folder',
|
|
env: {
|
|
GIT_CONFIG_COUNT: '3',
|
|
GIT_CONFIG_KEY_0: 'url.https://user:pass@example.com/.insteadOf',
|
|
GIT_CONFIG_KEY_1: 'url.https://user:pass@example.com/.insteadOf',
|
|
GIT_CONFIG_KEY_2: 'url.https://user:pass@example.com/.insteadOf',
|
|
GIT_CONFIG_VALUE_0: 'ssh://git@example.com/',
|
|
GIT_CONFIG_VALUE_1: 'git@example.com:',
|
|
GIT_CONFIG_VALUE_2: 'https://example.com/',
|
|
},
|
|
},
|
|
},
|
|
]);
|
|
});
|
|
});
|
|
});
|