mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-10 05:56:26 +00:00
Merge b1b1635886
into 141467b9b0
This commit is contained in:
commit
27add0b743
3 changed files with 142 additions and 8 deletions
|
@ -16,6 +16,10 @@ url = "last.url"
|
||||||
[[tool.poetry.source]]
|
[[tool.poetry.source]]
|
||||||
name = "five"
|
name = "five"
|
||||||
|
|
||||||
|
[[tool.poetry.source]]
|
||||||
|
name = "invalid-url"
|
||||||
|
url = "invalid-url"
|
||||||
|
|
||||||
[build-system]
|
[build-system]
|
||||||
requires = ["poetry_core>=1.0", "wheel"]
|
requires = ["poetry_core>=1.0", "wheel"]
|
||||||
build-backend = "poetry.masonry.api"
|
build-backend = "poetry.masonry.api"
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import { codeBlock } from 'common-tags';
|
import { codeBlock } from 'common-tags';
|
||||||
|
import { GoogleAuth as _googleAuth } from 'google-auth-library';
|
||||||
import { mockDeep } from 'jest-mock-extended';
|
import { mockDeep } from 'jest-mock-extended';
|
||||||
import { join } from 'upath';
|
import { join } from 'upath';
|
||||||
import { envMock, mockExecAll } from '../../../../test/exec-util';
|
import { envMock, mockExecAll } from '../../../../test/exec-util';
|
||||||
|
@ -15,16 +16,26 @@ import { updateArtifacts } from '.';
|
||||||
|
|
||||||
const pyproject1toml = Fixtures.get('pyproject.1.toml');
|
const pyproject1toml = Fixtures.get('pyproject.1.toml');
|
||||||
const pyproject10toml = Fixtures.get('pyproject.10.toml');
|
const pyproject10toml = Fixtures.get('pyproject.10.toml');
|
||||||
|
const pyproject13toml = `[[tool.poetry.source]]
|
||||||
|
name = "some-gar-repo"
|
||||||
|
url = "https://someregion-python.pkg.dev/some-project/some-repo/simple/"
|
||||||
|
|
||||||
|
[build-system]
|
||||||
|
requires = ["poetry_core>=1.0", "wheel"]
|
||||||
|
build-backend = "poetry.masonry.api"
|
||||||
|
`;
|
||||||
|
|
||||||
jest.mock('../../../util/exec/env');
|
jest.mock('../../../util/exec/env');
|
||||||
jest.mock('../../../util/fs');
|
jest.mock('../../../util/fs');
|
||||||
jest.mock('../../datasource', () => mockDeep());
|
jest.mock('../../datasource', () => mockDeep());
|
||||||
jest.mock('../../../util/host-rules', () => mockDeep());
|
jest.mock('../../../util/host-rules', () => mockDeep());
|
||||||
|
jest.mock('google-auth-library');
|
||||||
|
|
||||||
process.env.CONTAINERBASE = 'true';
|
process.env.CONTAINERBASE = 'true';
|
||||||
|
|
||||||
const datasource = mocked(_datasource);
|
const datasource = mocked(_datasource);
|
||||||
const hostRules = mocked(_hostRules);
|
const hostRules = mocked(_hostRules);
|
||||||
|
const googleAuth = mocked(_googleAuth);
|
||||||
|
|
||||||
const adminConfig: RepoGlobalConfig = {
|
const adminConfig: RepoGlobalConfig = {
|
||||||
localDir: join('/tmp/github/some/repo'),
|
localDir: join('/tmp/github/some/repo'),
|
||||||
|
@ -198,7 +209,99 @@ describe('modules/manager/poetry/artifacts', () => {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
]);
|
]);
|
||||||
expect(hostRules.find.mock.calls).toHaveLength(5);
|
expect(hostRules.find.mock.calls).toHaveLength(7);
|
||||||
|
expect(execSnapshots).toMatchObject([
|
||||||
|
{
|
||||||
|
cmd: 'poetry update --lock --no-interaction dep1',
|
||||||
|
options: {
|
||||||
|
env: {
|
||||||
|
POETRY_HTTP_BASIC_ONE_PASSWORD: 'passwordOne',
|
||||||
|
POETRY_HTTP_BASIC_ONE_USERNAME: 'usernameOne',
|
||||||
|
POETRY_HTTP_BASIC_TWO_USERNAME: 'usernameTwo',
|
||||||
|
POETRY_HTTP_BASIC_FOUR_OH_FOUR_PASSWORD: 'passwordFour',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('passes Google Artifact Registry credentials environment vars', async () => {
|
||||||
|
// poetry.lock
|
||||||
|
fs.getSiblingFileName.mockReturnValueOnce('poetry.lock');
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce(null);
|
||||||
|
// pyproject.lock
|
||||||
|
fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock');
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce('[metadata]\n');
|
||||||
|
const execSnapshots = mockExecAll();
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce('New poetry.lock');
|
||||||
|
googleAuth.mockImplementationOnce(
|
||||||
|
jest.fn().mockImplementationOnce(() => ({
|
||||||
|
getAccessToken: jest.fn().mockResolvedValue('some-token'),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
const updatedDeps = [{ depName: 'dep1' }];
|
||||||
|
expect(
|
||||||
|
await updateArtifacts({
|
||||||
|
packageFileName: 'pyproject.toml',
|
||||||
|
updatedDeps,
|
||||||
|
newPackageFileContent: pyproject13toml,
|
||||||
|
config,
|
||||||
|
}),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
file: {
|
||||||
|
type: 'addition',
|
||||||
|
path: 'pyproject.lock',
|
||||||
|
contents: 'New poetry.lock',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
expect(hostRules.find.mock.calls).toHaveLength(3);
|
||||||
|
expect(execSnapshots).toMatchObject([
|
||||||
|
{
|
||||||
|
cmd: 'poetry update --lock --no-interaction dep1',
|
||||||
|
options: {
|
||||||
|
env: {
|
||||||
|
POETRY_HTTP_BASIC_SOME_GAR_REPO_USERNAME: 'oauth2accesstoken',
|
||||||
|
POETRY_HTTP_BASIC_SOME_GAR_REPO_PASSWORD: 'some-token',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('continues if Google auth is not configured', async () => {
|
||||||
|
// poetry.lock
|
||||||
|
fs.getSiblingFileName.mockReturnValueOnce('poetry.lock');
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce(null);
|
||||||
|
// pyproject.lock
|
||||||
|
fs.getSiblingFileName.mockReturnValueOnce('pyproject.lock');
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce('[metadata]\n');
|
||||||
|
const execSnapshots = mockExecAll();
|
||||||
|
fs.readLocalFile.mockResolvedValueOnce('New poetry.lock');
|
||||||
|
googleAuth.mockImplementation(
|
||||||
|
jest.fn().mockImplementation(() => ({
|
||||||
|
getAccessToken: jest.fn().mockResolvedValue(undefined),
|
||||||
|
})),
|
||||||
|
);
|
||||||
|
const updatedDeps = [{ depName: 'dep1' }];
|
||||||
|
expect(
|
||||||
|
await updateArtifacts({
|
||||||
|
packageFileName: 'pyproject.toml',
|
||||||
|
updatedDeps,
|
||||||
|
newPackageFileContent: pyproject13toml,
|
||||||
|
config,
|
||||||
|
}),
|
||||||
|
).toEqual([
|
||||||
|
{
|
||||||
|
file: {
|
||||||
|
type: 'addition',
|
||||||
|
path: 'pyproject.lock',
|
||||||
|
contents: 'New poetry.lock',
|
||||||
|
},
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
expect(hostRules.find.mock.calls).toHaveLength(3);
|
||||||
expect(execSnapshots).toMatchObject([
|
expect(execSnapshots).toMatchObject([
|
||||||
{ cmd: 'poetry update --lock --no-interaction dep1' },
|
{ cmd: 'poetry update --lock --no-interaction dep1' },
|
||||||
]);
|
]);
|
||||||
|
|
|
@ -17,7 +17,9 @@ import { find } from '../../../util/host-rules';
|
||||||
import { regEx } from '../../../util/regex';
|
import { regEx } from '../../../util/regex';
|
||||||
import { Result } from '../../../util/result';
|
import { Result } from '../../../util/result';
|
||||||
import { parse as parseToml } from '../../../util/toml';
|
import { parse as parseToml } from '../../../util/toml';
|
||||||
|
import { parseUrl } from '../../../util/url';
|
||||||
import { PypiDatasource } from '../../datasource/pypi';
|
import { PypiDatasource } from '../../datasource/pypi';
|
||||||
|
import { getGoogleAuthTokenRaw } from '../../datasource/util';
|
||||||
import type { UpdateArtifact, UpdateArtifactsResult } from '../types';
|
import type { UpdateArtifact, UpdateArtifactsResult } from '../types';
|
||||||
import { Lockfile, PoetrySchemaToml } from './schema';
|
import { Lockfile, PoetrySchemaToml } from './schema';
|
||||||
import type { PoetryFile, PoetrySource } from './types';
|
import type { PoetryFile, PoetrySource } from './types';
|
||||||
|
@ -101,7 +103,7 @@ function getPoetrySources(content: string, fileName: string): PoetrySource[] {
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
if (!pyprojectFile.tool?.poetry) {
|
if (!pyprojectFile.tool?.poetry) {
|
||||||
logger.debug(`{$fileName} contains no poetry section`);
|
logger.debug(`${fileName} contains no poetry section`);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,20 +117,42 @@ function getPoetrySources(content: string, fileName: string): PoetrySource[] {
|
||||||
return sourceArray;
|
return sourceArray;
|
||||||
}
|
}
|
||||||
|
|
||||||
function getMatchingHostRule(url: string | undefined): HostRule {
|
async function getMatchingHostRule(url: string | undefined): Promise<HostRule> {
|
||||||
const scopedMatch = find({ hostType: PypiDatasource.id, url });
|
const scopedMatch = find({ hostType: PypiDatasource.id, url });
|
||||||
return is.nonEmptyObject(scopedMatch) ? scopedMatch : find({ url });
|
const hostRule = is.nonEmptyObject(scopedMatch) ? scopedMatch : find({ url });
|
||||||
|
if (hostRule) {
|
||||||
|
return hostRule;
|
||||||
|
}
|
||||||
|
|
||||||
|
const parsedUrl = parseUrl(url);
|
||||||
|
if (!parsedUrl) {
|
||||||
|
logger.once.debug(`Failed to parse URL ${url}`);
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parsedUrl.hostname.endsWith('.pkg.dev')) {
|
||||||
|
const accessToken = await getGoogleAuthTokenRaw();
|
||||||
|
if (accessToken) {
|
||||||
|
return {
|
||||||
|
username: 'oauth2accesstoken',
|
||||||
|
password: accessToken,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
logger.once.debug(`Could not get Google access token (url=${url})`);
|
||||||
|
}
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
function getSourceCredentialVars(
|
async function getSourceCredentialVars(
|
||||||
pyprojectContent: string,
|
pyprojectContent: string,
|
||||||
packageFileName: string,
|
packageFileName: string,
|
||||||
): NodeJS.ProcessEnv {
|
): Promise<NodeJS.ProcessEnv> {
|
||||||
const poetrySources = getPoetrySources(pyprojectContent, packageFileName);
|
const poetrySources = getPoetrySources(pyprojectContent, packageFileName);
|
||||||
const envVars: NodeJS.ProcessEnv = {};
|
const envVars: NodeJS.ProcessEnv = {};
|
||||||
|
|
||||||
for (const source of poetrySources) {
|
for (const source of poetrySources) {
|
||||||
const matchingHostRule = getMatchingHostRule(source.url);
|
const matchingHostRule = await getMatchingHostRule(source.url);
|
||||||
const formattedSourceName = source.name
|
const formattedSourceName = source.name
|
||||||
.replace(regEx(/(\.|-)+/g), '_')
|
.replace(regEx(/(\.|-)+/g), '_')
|
||||||
.toUpperCase();
|
.toUpperCase();
|
||||||
|
@ -192,7 +216,10 @@ export async function updateArtifacts({
|
||||||
config.constraints?.poetry ??
|
config.constraints?.poetry ??
|
||||||
getPoetryRequirement(newPackageFileContent, existingLockFileContent);
|
getPoetryRequirement(newPackageFileContent, existingLockFileContent);
|
||||||
const extraEnv = {
|
const extraEnv = {
|
||||||
...getSourceCredentialVars(newPackageFileContent, packageFileName),
|
...(await getSourceCredentialVars(
|
||||||
|
newPackageFileContent,
|
||||||
|
packageFileName,
|
||||||
|
)),
|
||||||
...getGitEnvironmentVariables(['poetry']),
|
...getGitEnvironmentVariables(['poetry']),
|
||||||
PIP_CACHE_DIR: await ensureCacheDir('pip'),
|
PIP_CACHE_DIR: await ensureCacheDir('pip'),
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in a new issue