mirror of
https://github.com/renovatebot/renovate.git
synced 2025-01-12 15:06:27 +00:00
feat(manager/dockerfile): add support for registryAliases (#17139)
Co-authored-by: Rhys Arkins <rhys@arkins.net> Co-authored-by: Niko Hass <nikohass571@gmail.com> Co-authored-by: Niko Haß <48032410+nikohass@users.noreply.github.com> Co-authored-by: Michael Kriese <michael.kriese@visualon.de>
This commit is contained in:
parent
a3c8e2087d
commit
551a40ccab
14 changed files with 604 additions and 84 deletions
|
@ -2525,6 +2525,11 @@ This feature works with the following managers:
|
|||
- [`helmv3`](/modules/manager/helmv3/)
|
||||
- [`helmfile`](/modules/manager/helmfile/)
|
||||
- [`gitlabci`](/modules/manager/gitlabci/)
|
||||
- [`dockerfile`](/modules/manager/dockerfile)
|
||||
- [`docker-compose`](/modules/manager/docker-compose)
|
||||
- [`kubernetes`](/modules/manager/kubernetes)
|
||||
- [`ansible`](/modules/manager/ansible)
|
||||
- [`droneci`](/modules/manager/droneci)
|
||||
|
||||
## registryUrls
|
||||
|
||||
|
|
|
@ -822,7 +822,17 @@ const options: RenovateOptions[] = [
|
|||
type: 'string',
|
||||
format: 'uri',
|
||||
},
|
||||
supportedManagers: ['helm-requirements', 'helmv3', 'helmfile', 'gitlabci'],
|
||||
supportedManagers: [
|
||||
'helm-requirements',
|
||||
'helmv3',
|
||||
'helmfile',
|
||||
'gitlabci',
|
||||
'dockerfile',
|
||||
'docker-compose',
|
||||
'kubernetes',
|
||||
'ansible',
|
||||
'droneci',
|
||||
],
|
||||
},
|
||||
{
|
||||
name: 'defaultRegistryUrls',
|
||||
|
|
|
@ -4,19 +4,110 @@ import { extractPackageFile } from '.';
|
|||
describe('modules/manager/ansible/extract', () => {
|
||||
describe('extractPackageFile()', () => {
|
||||
it('returns null for empty', () => {
|
||||
expect(extractPackageFile('nothing here')).toBeNull();
|
||||
expect(extractPackageFile('nothing here', '', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('extracts multiple image lines from docker_container', () => {
|
||||
const res = extractPackageFile(Fixtures.get('main1.yaml'));
|
||||
const res = extractPackageFile(Fixtures.get('main1.yaml'), '', {});
|
||||
expect(res?.deps).toMatchSnapshot();
|
||||
expect(res?.deps).toHaveLength(9);
|
||||
});
|
||||
|
||||
it('extracts multiple image lines from docker_service', () => {
|
||||
const res = extractPackageFile(Fixtures.get('main2.yaml'));
|
||||
const res = extractPackageFile(Fixtures.get('main2.yaml'), '', {});
|
||||
expect(res?.deps).toMatchSnapshot();
|
||||
expect(res?.deps).toHaveLength(4);
|
||||
});
|
||||
|
||||
it('extracts image and replaces registry', () => {
|
||||
const res = extractPackageFile(
|
||||
`---
|
||||
- name: Re-create a redis container
|
||||
docker_container:
|
||||
name: myredis
|
||||
image: quay.io/redis:0.0.1`,
|
||||
'',
|
||||
{
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/redis:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/redis',
|
||||
replaceString: 'quay.io/redis:0.0.1',
|
||||
versioning: 'docker',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts image but no replacement', () => {
|
||||
const res = extractPackageFile(
|
||||
`---
|
||||
- name: Re-create a redis container
|
||||
docker_container:
|
||||
name: myredis
|
||||
image: quay.io/redis:0.0.1`,
|
||||
'',
|
||||
{
|
||||
registryAliases: {
|
||||
'index.docker.io': 'my-docker-mirror.registry.com',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'quay.io/redis',
|
||||
replaceString: 'quay.io/redis:0.0.1',
|
||||
versioning: 'docker',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts image and no double replacement', () => {
|
||||
const res = extractPackageFile(
|
||||
`---
|
||||
- name: Re-create a redis container
|
||||
docker_container:
|
||||
name: myredis
|
||||
image: quay.io/redis:0.0.1`,
|
||||
'',
|
||||
{
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
'my-quay-mirror.registry.com': 'quay.io',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/redis:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/redis',
|
||||
replaceString: 'quay.io/redis:0.0.1',
|
||||
versioning: 'docker',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -2,9 +2,13 @@ import { logger } from '../../../logger';
|
|||
import { newlineRegex, regEx } from '../../../util/regex';
|
||||
import * as dockerVersioning from '../../versioning/docker';
|
||||
import { getDep } from '../dockerfile/extract';
|
||||
import type { PackageDependency, PackageFile } from '../types';
|
||||
import type { ExtractConfig, PackageDependency, PackageFile } from '../types';
|
||||
|
||||
export function extractPackageFile(content: string): PackageFile | null {
|
||||
export function extractPackageFile(
|
||||
content: string,
|
||||
_filename: string,
|
||||
config: ExtractConfig
|
||||
): PackageFile | null {
|
||||
logger.trace('ansible.extractPackageFile()');
|
||||
let deps: PackageDependency[] = [];
|
||||
const re = regEx(/^\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/);
|
||||
|
@ -12,7 +16,7 @@ export function extractPackageFile(content: string): PackageFile | null {
|
|||
const match = re.exec(line);
|
||||
if (match) {
|
||||
const currentFrom = match[1];
|
||||
const dep = getDep(currentFrom);
|
||||
const dep = getDep(currentFrom, true, config.registryAliases);
|
||||
logger.debug(
|
||||
{
|
||||
depName: dep.depName,
|
||||
|
|
|
@ -9,37 +9,37 @@ const yamlFile3DefaultValue = Fixtures.get('docker-compose.3-default-val.yml');
|
|||
describe('modules/manager/docker-compose/extract', () => {
|
||||
describe('extractPackageFile()', () => {
|
||||
it('returns null for empty', () => {
|
||||
expect(extractPackageFile('')).toBeNull();
|
||||
expect(extractPackageFile('', '', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for non-object YAML', () => {
|
||||
expect(extractPackageFile('nothing here')).toBeNull();
|
||||
expect(extractPackageFile('nothing here', '', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('returns null for malformed YAML', () => {
|
||||
expect(extractPackageFile('nothing here\n:::::::')).toBeNull();
|
||||
expect(extractPackageFile('nothing here\n:::::::', '', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('extracts multiple image lines for version 1', () => {
|
||||
const res = extractPackageFile(yamlFile1);
|
||||
const res = extractPackageFile(yamlFile1, '', {});
|
||||
expect(res?.deps).toMatchSnapshot();
|
||||
expect(res?.deps).toHaveLength(8);
|
||||
});
|
||||
|
||||
it('extracts multiple image lines for version 3', () => {
|
||||
const res = extractPackageFile(yamlFile3);
|
||||
const res = extractPackageFile(yamlFile3, '', {});
|
||||
expect(res?.deps).toMatchSnapshot();
|
||||
expect(res?.deps).toHaveLength(8);
|
||||
});
|
||||
|
||||
it('extracts multiple image lines for version 3 without set version key', () => {
|
||||
const res = extractPackageFile(yamlFile3NoVersion);
|
||||
const res = extractPackageFile(yamlFile3NoVersion, '', {});
|
||||
expect(res?.deps).toMatchSnapshot();
|
||||
expect(res?.deps).toHaveLength(8);
|
||||
});
|
||||
|
||||
it('extracts default variable values for version 3', () => {
|
||||
const res = extractPackageFile(yamlFile3DefaultValue);
|
||||
const res = extractPackageFile(yamlFile3DefaultValue, '', {});
|
||||
expect(res?.deps).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -54,5 +54,96 @@ describe('modules/manager/docker-compose/extract', () => {
|
|||
`);
|
||||
expect(res?.deps).toHaveLength(1);
|
||||
});
|
||||
|
||||
it('extracts image and replaces registry', () => {
|
||||
const res = extractPackageFile(
|
||||
`
|
||||
version: "3"
|
||||
services:
|
||||
nginx:
|
||||
image: quay.io/nginx:0.0.1
|
||||
`,
|
||||
'',
|
||||
{
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/nginx:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/nginx',
|
||||
replaceString: 'quay.io/nginx:0.0.1',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts image but no replacement', () => {
|
||||
const res = extractPackageFile(
|
||||
`
|
||||
version: "3"
|
||||
services:
|
||||
nginx:
|
||||
image: quay.io/nginx:0.0.1
|
||||
`,
|
||||
'',
|
||||
{
|
||||
registryAliases: {
|
||||
'index.docker.io': 'my-docker-mirror.registry.com',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'quay.io/nginx',
|
||||
replaceString: 'quay.io/nginx:0.0.1',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts image and no double replacement', () => {
|
||||
const res = extractPackageFile(
|
||||
`
|
||||
version: "3"
|
||||
services:
|
||||
nginx:
|
||||
image: quay.io/nginx:0.0.1
|
||||
`,
|
||||
'',
|
||||
{
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
'my-quay-mirror.registry.com': 'quay.io',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/nginx:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/nginx',
|
||||
replaceString: 'quay.io/nginx:0.0.1',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,7 +3,7 @@ import { load } from 'js-yaml';
|
|||
import { logger } from '../../../logger';
|
||||
import { newlineRegex, regEx } from '../../../util/regex';
|
||||
import { getDep } from '../dockerfile/extract';
|
||||
import type { PackageFile } from '../types';
|
||||
import type { ExtractConfig, PackageFile } from '../types';
|
||||
import type { DockerComposeConfig } from './types';
|
||||
|
||||
class LineMapper {
|
||||
|
@ -30,7 +30,8 @@ class LineMapper {
|
|||
|
||||
export function extractPackageFile(
|
||||
content: string,
|
||||
fileName?: string
|
||||
fileName: string,
|
||||
extractConfig: ExtractConfig
|
||||
): PackageFile | null {
|
||||
logger.debug('docker-compose.extractPackageFile()');
|
||||
let config: DockerComposeConfig;
|
||||
|
@ -71,7 +72,7 @@ export function extractPackageFile(
|
|||
const deps = Object.values(services || {})
|
||||
.filter((service) => is.string(service?.image) && !service?.build)
|
||||
.map((service) => {
|
||||
const dep = getDep(service.image);
|
||||
const dep = getDep(service.image, true, extractConfig.registryAliases);
|
||||
const lineNumber = lineMapper.pluckLineNumber(service.image);
|
||||
// istanbul ignore if
|
||||
if (!lineNumber) {
|
||||
|
|
|
@ -11,12 +11,12 @@ const d4 = Fixtures.get('4.Dockerfile');
|
|||
describe('modules/manager/dockerfile/extract', () => {
|
||||
describe('extractPackageFile()', () => {
|
||||
it('handles no FROM', () => {
|
||||
const res = extractPackageFile('no from!');
|
||||
const res = extractPackageFile('no from!', '', {});
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
|
||||
it('handles naked dep', () => {
|
||||
const res = extractPackageFile('FROM node\n')?.deps;
|
||||
const res = extractPackageFile('FROM node\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -33,7 +33,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('is case insensitive', () => {
|
||||
const res = extractPackageFile('From node\n')?.deps;
|
||||
const res = extractPackageFile('From node\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -50,7 +50,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles tag', () => {
|
||||
const res = extractPackageFile('FROM node:8.9.0-alpine\n')?.deps;
|
||||
const res = extractPackageFile('FROM node:8.9.0-alpine\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -68,7 +68,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles digest', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM node@sha256:eb85fc5b1198f5e1ec025ea07586bdbbf397e7d82df66c90d7511f533517e063\n'
|
||||
'FROM node@sha256:eb85fc5b1198f5e1ec025ea07586bdbbf397e7d82df66c90d7511f533517e063\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -87,7 +89,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles tag and digest', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM node:8.9.0@sha256:eb85fc5b1198f5e1ec025ea07586bdbbf397e7d82df66c90d7511f533517e063\n'
|
||||
'FROM node:8.9.0@sha256:eb85fc5b1198f5e1ec025ea07586bdbbf397e7d82df66c90d7511f533517e063\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -105,7 +109,11 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles from as', () => {
|
||||
const res = extractPackageFile('FROM node:8.9.0-alpine as base\n')?.deps;
|
||||
const res = extractPackageFile(
|
||||
'FROM node:8.9.0-alpine as base\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -123,7 +131,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles comments', () => {
|
||||
const res = extractPackageFile(
|
||||
'# some comment\n# another\n\nFROM node\n'
|
||||
'# some comment\n# another\n\nFROM node\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -142,7 +152,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles custom hosts', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM registry2.something.info/node:8\n'
|
||||
'FROM registry2.something.info/node:8\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -161,7 +173,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles custom hosts and suffix', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM registry2.something.info/node:8-alpine\n'
|
||||
'FROM registry2.something.info/node:8-alpine\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -180,7 +194,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles custom hosts with port', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM registry2.something.info:5005/node:8\n'
|
||||
'FROM registry2.something.info:5005/node:8\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -201,7 +217,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles custom hosts with port without tag', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM registry2.something.info:5005/node\n'
|
||||
'FROM registry2.something.info:5005/node\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -220,7 +238,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles quay hosts with port', () => {
|
||||
const res = extractPackageFile('FROM quay.io:1234/node\n')?.deps;
|
||||
const res = extractPackageFile('FROM quay.io:1234/node\n', '', {})?.deps;
|
||||
expect(res?.[0]).toMatchInlineSnapshot(`
|
||||
{
|
||||
"autoReplaceStringTemplate": "{{packageName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}",
|
||||
|
@ -236,7 +254,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles namespaced images', () => {
|
||||
const res = extractPackageFile('FROM mynamespace/node:8\n')?.deps;
|
||||
const res = extractPackageFile('FROM mynamespace/node:8\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -254,7 +272,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles custom hosts with namespace', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM registry2.something.info/someaccount/node:8\n'
|
||||
'FROM registry2.something.info/someaccount/node:8\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -273,7 +293,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles abnormal spacing', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM registry.allmine.info:5005/node:8.7.0\n\n'
|
||||
'FROM registry.allmine.info:5005/node:8.7.0\n\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -292,7 +314,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('extracts multiple FROM tags', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nFROM python:3.6-slim\n'
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nFROM python:3.6-slim\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -320,13 +344,15 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('skips scratches', () => {
|
||||
const res = extractPackageFile('FROM scratch\nADD foo\n');
|
||||
const res = extractPackageFile('FROM scratch\nADD foo\n', '', {});
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
|
||||
it('skips named multistage FROM tags', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nFROM frontend\n'
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nFROM frontend\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -346,7 +372,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles COPY --from', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM scratch\nCOPY --from=gcr.io/k8s-skaffold/skaffold:v0.11.0 /usr/bin/skaffold /usr/bin/skaffold\n'
|
||||
'FROM scratch\nCOPY --from=gcr.io/k8s-skaffold/skaffold:v0.11.0 /usr/bin/skaffold /usr/bin/skaffold\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -365,7 +393,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('skips named multistage COPY --from tags', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nCOPY --from=frontend /usr/bin/node /usr/bin/node\n'
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nCOPY --from=frontend /usr/bin/node /usr/bin/node\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -385,7 +415,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('skips index reference COPY --from tags', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nCOPY --from=0 /usr/bin/node /usr/bin/node\n'
|
||||
'FROM node:6.12.3 as frontend\n\n# comment\nENV foo=bar\nCOPY --from=0 /usr/bin/node /usr/bin/node\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -405,7 +437,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('detects ["stage"] and ["final"] deps of docker multi-stage build.', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM node:8.15.1-alpine as skippedfrom\nFROM golang:1.7.3 as builder\n\n# comment\nWORKDIR /go/src/github.com/alexellis/href-counter/\nRUN go get -d -v golang.org/x/net/html \nCOPY app.go .\nRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .\n\nFROM alpine:latest \nRUN apk --no-cache add ca-certificates\nWORKDIR /root/\nCOPY --from=builder /go/src/github.com/alexellis/href-counter/app .\nCMD ["./app"]\n'
|
||||
'FROM node:8.15.1-alpine as skippedfrom\nFROM golang:1.7.3 as builder\n\n# comment\nWORKDIR /go/src/github.com/alexellis/href-counter/\nRUN go get -d -v golang.org/x/net/html \nCOPY app.go .\nRUN CGO_ENABLED=0 GOOS=linux go build -a -installsuffix cgo -o app .\n\nFROM alpine:latest \nRUN apk --no-cache add ca-certificates\nWORKDIR /root/\nCOPY --from=builder /go/src/github.com/alexellis/href-counter/app .\nCMD ["./app"]\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -447,7 +481,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('extracts images on adjacent lines', () => {
|
||||
const res = extractPackageFile(d1)?.deps;
|
||||
const res = extractPackageFile(d1, '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -474,7 +508,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('extracts images from all sorts of (maybe multiline) FROM and COPY --from statements', () => {
|
||||
const res = extractPackageFile(d2)?.deps;
|
||||
const res = extractPackageFile(d2, '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -564,7 +598,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles calico/node', () => {
|
||||
const res = extractPackageFile('FROM calico/node\n')?.deps;
|
||||
const res = extractPackageFile('FROM calico/node\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -581,7 +615,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles ubuntu', () => {
|
||||
const res = extractPackageFile('FROM ubuntu:18.04\n')?.deps;
|
||||
const res = extractPackageFile('FROM ubuntu:18.04\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -599,7 +633,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles debian with codename', () => {
|
||||
const res = extractPackageFile('FROM debian:buster\n')?.deps;
|
||||
const res = extractPackageFile('FROM debian:buster\n', '', {})?.deps;
|
||||
expect(res).toEqual([
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
|
@ -616,7 +650,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles debian with prefixes', () => {
|
||||
const res = extractPackageFile('FROM amd64/debian:10\n')?.deps;
|
||||
const res = extractPackageFile('FROM amd64/debian:10\n', '', {})?.deps;
|
||||
expect(res).toEqual([
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
|
@ -634,7 +668,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles prefixes', () => {
|
||||
const res = extractPackageFile('FROM amd64/ubuntu:18.04\n')?.deps;
|
||||
const res = extractPackageFile('FROM amd64/ubuntu:18.04\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -654,7 +688,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles implausible line continuation', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM alpine:3.5\n\nRUN something \\'
|
||||
'FROM alpine:3.5\n\nRUN something \\',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -672,7 +708,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles multi-line FROM with space after escape character', () => {
|
||||
const res = extractPackageFile('FROM \\ \nnginx:1.20\n')?.deps;
|
||||
const res = extractPackageFile('FROM \\ \nnginx:1.20\n', '', {})?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -689,7 +725,11 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles FROM without ARG default value', () => {
|
||||
const res = extractPackageFile('ARG img_base\nFROM $img_base\n')?.deps;
|
||||
const res = extractPackageFile(
|
||||
'ARG img_base\nFROM $img_base\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
{
|
||||
|
@ -705,7 +745,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles FROM with empty ARG default value', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG patch1=""\nARG patch2=\nFROM nginx:1.20${patch1}$patch2\n'
|
||||
'ARG patch1=""\nARG patch2=\nFROM nginx:1.20${patch1}$patch2\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -724,7 +766,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles FROM with version in ARG value', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG\tVARIANT="1.60.0-bullseye"\nFROM\trust:${VARIANT}\n'
|
||||
'ARG\tVARIANT="1.60.0-bullseye"\nFROM\trust:${VARIANT}\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -743,7 +787,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles FROM with version in ARG default value', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG IMAGE_VERSION=${IMAGE_VERSION:-ubuntu:xenial}\nfrom ${IMAGE_VERSION} as base\n'
|
||||
'ARG IMAGE_VERSION=${IMAGE_VERSION:-ubuntu:xenial}\nfrom ${IMAGE_VERSION} as base\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -763,7 +809,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
it('handles FROM with digest in ARG default value', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG sha_digest=sha256:ab37242e81cbc031b2600eef4440fe87055a05c14b40686df85078cc5086c98f\n' +
|
||||
' FROM gcr.io/distroless/java17@$sha_digest'
|
||||
' FROM gcr.io/distroless/java17@$sha_digest',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -782,7 +830,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles FROM with overwritten ARG value', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG base=nginx:1.19\nFROM $base as stage1\nARG base=nginx:1.20\nFROM --platform=amd64 $base as stage2\n'
|
||||
'ARG base=nginx:1.19\nFROM $base as stage1\nARG base=nginx:1.20\nFROM --platform=amd64 $base as stage2\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -810,7 +860,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles FROM with multiple ARG values', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG CUDA=9.2\nARG LINUX_VERSION ubuntu16.04\nFROM nvidia/cuda:${CUDA}-devel-${LINUX_VERSION}\n'
|
||||
'ARG CUDA=9.2\nARG LINUX_VERSION ubuntu16.04\nFROM nvidia/cuda:${CUDA}-devel-${LINUX_VERSION}\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -828,12 +880,16 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('skips scratch if provided in ARG value', () => {
|
||||
const res = extractPackageFile('ARG img="scratch"\nFROM $img as base\n');
|
||||
const res = extractPackageFile(
|
||||
'ARG img="scratch"\nFROM $img as base\n',
|
||||
'',
|
||||
{}
|
||||
);
|
||||
expect(res).toBeNull();
|
||||
});
|
||||
|
||||
it('extracts images from multi-line ARG statements', () => {
|
||||
const res = extractPackageFile(d3)?.deps;
|
||||
const res = extractPackageFile(d3, '', {})?.deps;
|
||||
expect(res).toEqual([
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
|
@ -875,7 +931,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('ignores parser directives in wrong order', () => {
|
||||
const res = extractPackageFile(
|
||||
'# dummy\n# escape = `\n\nFROM\\\nnginx:1.20'
|
||||
'# dummy\n# escape = `\n\nFROM\\\nnginx:1.20',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -893,7 +951,7 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
|
||||
it('handles an alternative escape character', () => {
|
||||
const res = extractPackageFile(d4)?.deps;
|
||||
const res = extractPackageFile(d4, '', {})?.deps;
|
||||
expect(res).toEqual([
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
|
@ -954,7 +1012,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles FROM with version in ARG default value and quotes', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG REF_NAME=${REF_NAME:-"gcr.io/distroless/static-debian11:nonroot@sha256:abc"}\nfrom ${REF_NAME}'
|
||||
'ARG REF_NAME=${REF_NAME:-"gcr.io/distroless/static-debian11:nonroot@sha256:abc"}\nfrom ${REF_NAME}',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toMatchInlineSnapshot(`
|
||||
[
|
||||
|
@ -973,7 +1033,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
|
||||
it('handles version in ARG and digest in FROM with CRLF linefeed', () => {
|
||||
const res = extractPackageFile(
|
||||
'ARG IMAGE_TAG=14.04\r\n#something unrelated\r\nFROM ubuntu:$IMAGE_TAG@sha256:abc\r\n'
|
||||
'ARG IMAGE_TAG=14.04\r\n#something unrelated\r\nFROM ubuntu:$IMAGE_TAG@sha256:abc\r\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toEqual([
|
||||
{
|
||||
|
@ -999,7 +1061,9 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
'ARG NODE_IMAGE_NAME=node\n' +
|
||||
'ARG NODE_IMAGE_TAG="16.14.2-alpine3.14"\n' +
|
||||
'ARG DUMMY_PREFIX=\n' +
|
||||
'FROM ${DUMMY_PREFIX}${NODE_IMAGE_HOST}${NODE_IMAGE_NAME}:${NODE_IMAGE_TAG}${NODE_IMAGE_HASH} as yarn\n'
|
||||
'FROM ${DUMMY_PREFIX}${NODE_IMAGE_HOST}${NODE_IMAGE_NAME}:${NODE_IMAGE_TAG}${NODE_IMAGE_HASH} as yarn\n',
|
||||
'',
|
||||
{}
|
||||
)?.deps;
|
||||
expect(res).toEqual([
|
||||
{
|
||||
|
@ -1024,6 +1088,82 @@ describe('modules/manager/dockerfile/extract', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('handles empty optional parameters', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM quay.io/myName/myPackage:0.6.2\n',
|
||||
'',
|
||||
{}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.6.2',
|
||||
datasource: 'docker',
|
||||
depName: 'quay.io/myName/myPackage',
|
||||
depType: 'final',
|
||||
replaceString: 'quay.io/myName/myPackage:0.6.2',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('handles registry alias', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM quay.io/myName/myPackage:0.6.2\n',
|
||||
'Dockerfile',
|
||||
{
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
'index.docker.io': 'my-docker-mirror.registry.com',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/myName/myPackage:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.6.2',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/myName/myPackage',
|
||||
depType: 'final',
|
||||
replaceString: 'quay.io/myName/myPackage:0.6.2',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('handles empty registry', () => {
|
||||
const res = extractPackageFile(
|
||||
'FROM myName/myPackage:0.6.2\n',
|
||||
'Dockerfile',
|
||||
{
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
'index.docker.io': 'my-docker-mirror.registry.com',
|
||||
},
|
||||
}
|
||||
);
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.6.2',
|
||||
datasource: 'docker',
|
||||
depName: 'myName/myPackage',
|
||||
depType: 'final',
|
||||
replaceString: 'myName/myPackage:0.6.2',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
describe('getDep()', () => {
|
||||
it('rejects null', () => {
|
||||
expect(getDep(null)).toEqual({ skipReason: 'invalid-value' });
|
||||
|
|
|
@ -4,7 +4,7 @@ import { escapeRegExp, newlineRegex, regEx } from '../../../util/regex';
|
|||
import { DockerDatasource } from '../../datasource/docker';
|
||||
import * as debianVersioning from '../../versioning/debian';
|
||||
import * as ubuntuVersioning from '../../versioning/ubuntu';
|
||||
import type { PackageDependency, PackageFile } from '../types';
|
||||
import type { ExtractConfig, PackageDependency, PackageFile } from '../types';
|
||||
|
||||
const variableMarker = '$';
|
||||
|
||||
|
@ -226,7 +226,11 @@ export function getDep(
|
|||
return dep;
|
||||
}
|
||||
|
||||
export function extractPackageFile(content: string): PackageFile | null {
|
||||
export function extractPackageFile(
|
||||
content: string,
|
||||
_filename: string,
|
||||
config: ExtractConfig
|
||||
): PackageFile | null {
|
||||
const deps: PackageDependency[] = [];
|
||||
const stageNames: string[] = [];
|
||||
const args: Record<string, string> = {};
|
||||
|
@ -322,7 +326,7 @@ export function extractPackageFile(content: string): PackageFile | null {
|
|||
} else if (fromImage && stageNames.includes(fromImage)) {
|
||||
logger.debug({ image: fromImage }, 'Skipping alias FROM');
|
||||
} else {
|
||||
const dep = getDep(fromImage);
|
||||
const dep = getDep(fromImage, true, config.registryAliases);
|
||||
processDepForAutoReplace(dep, lineNumberRanges, lines, lineFeed);
|
||||
logger.trace(
|
||||
{
|
||||
|
@ -350,7 +354,11 @@ export function extractPackageFile(content: string): PackageFile | null {
|
|||
'Skipping alias COPY --from'
|
||||
);
|
||||
} else if (Number.isNaN(Number(copyFromMatch.groups.image))) {
|
||||
const dep = getDep(copyFromMatch.groups.image);
|
||||
const dep = getDep(
|
||||
copyFromMatch.groups.image,
|
||||
true,
|
||||
config.registryAliases
|
||||
);
|
||||
const lineNumberRanges: number[][] = [
|
||||
[lineNumberInstrStart, lineNumber],
|
||||
];
|
||||
|
|
8
lib/modules/manager/droneci/__fixtures__/.drone2.yml
Normal file
8
lib/modules/manager/droneci/__fixtures__/.drone2.yml
Normal file
|
@ -0,0 +1,8 @@
|
|||
kind: pipeline
|
||||
name: Test
|
||||
|
||||
steps:
|
||||
- name: mix
|
||||
image: quay.io/elixir:1.8.1-alpine
|
||||
environment:
|
||||
DB_HOST: mysql
|
|
@ -2,16 +2,85 @@ import { Fixtures } from '../../../../test/fixtures';
|
|||
|
||||
import { extractPackageFile } from '.';
|
||||
|
||||
const droneciRegistryAlias = Fixtures.get('.drone2.yml');
|
||||
|
||||
describe('modules/manager/droneci/extract', () => {
|
||||
describe('extractPackageFile()', () => {
|
||||
it('returns null for empty', () => {
|
||||
expect(extractPackageFile('nothing here')).toBeNull();
|
||||
expect(extractPackageFile('nothing here', '', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('extracts multiple image lines', () => {
|
||||
const res = extractPackageFile(Fixtures.get('.drone.yml'));
|
||||
const res = extractPackageFile(Fixtures.get('.drone.yml'), '', {});
|
||||
expect(res?.deps).toMatchSnapshot();
|
||||
expect(res?.deps).toHaveLength(6);
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts image and replaces registry', () => {
|
||||
const res = extractPackageFile(droneciRegistryAlias, '', {
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
},
|
||||
});
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/elixir:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '1.8.1-alpine',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/elixir',
|
||||
replaceString: 'quay.io/elixir:1.8.1-alpine',
|
||||
depType: 'docker',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts image but no replacement', () => {
|
||||
const res = extractPackageFile(droneciRegistryAlias, '', {
|
||||
registryAliases: {
|
||||
'index.docker.io': 'my-docker-mirror.registry.com',
|
||||
},
|
||||
});
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '1.8.1-alpine',
|
||||
datasource: 'docker',
|
||||
depName: 'quay.io/elixir',
|
||||
replaceString: 'quay.io/elixir:1.8.1-alpine',
|
||||
depType: 'docker',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts image and no double replacement', () => {
|
||||
const res = extractPackageFile(droneciRegistryAlias, '', {
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
'my-quay-mirror.registry.com': 'quay.io',
|
||||
},
|
||||
});
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/elixir:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '1.8.1-alpine',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/elixir',
|
||||
replaceString: 'quay.io/elixir:1.8.1-alpine',
|
||||
depType: 'docker',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,9 +1,13 @@
|
|||
import { logger } from '../../../logger';
|
||||
import { newlineRegex, regEx } from '../../../util/regex';
|
||||
import { getDep } from '../dockerfile/extract';
|
||||
import type { PackageDependency, PackageFile } from '../types';
|
||||
import type { ExtractConfig, PackageDependency, PackageFile } from '../types';
|
||||
|
||||
export function extractPackageFile(content: string): PackageFile | null {
|
||||
export function extractPackageFile(
|
||||
content: string,
|
||||
_filename: string,
|
||||
config: ExtractConfig
|
||||
): PackageFile | null {
|
||||
const deps: PackageDependency[] = [];
|
||||
try {
|
||||
const lines = content.split(newlineRegex);
|
||||
|
@ -34,7 +38,7 @@ export function extractPackageFile(content: string): PackageFile | null {
|
|||
currentFrom += finalLineMatch.groups.currentFrom;
|
||||
replaceString += '\n' + finalLineMatch.groups.replaceString;
|
||||
|
||||
const dep = getDep(currentFrom);
|
||||
const dep = getDep(currentFrom, true, config.registryAliases);
|
||||
dep.depType = 'docker';
|
||||
dep.replaceString = replaceString;
|
||||
if (dep.autoReplaceStringTemplate) {
|
||||
|
@ -54,7 +58,11 @@ export function extractPackageFile(content: string): PackageFile | null {
|
|||
/^\s* image:\s*'?"?(?<currentFrom>[^\s'"]+)'?"?\s*$/
|
||||
).exec(line);
|
||||
if (match?.groups) {
|
||||
const dep = getDep(match.groups.currentFrom);
|
||||
const dep = getDep(
|
||||
match.groups.currentFrom,
|
||||
true,
|
||||
config.registryAliases
|
||||
);
|
||||
dep.depType = 'docker';
|
||||
deps.push(dep);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: node-pod
|
||||
labels:
|
||||
app: node
|
||||
spec:
|
||||
containers:
|
||||
- name: node
|
||||
image: quay.io/node:0.0.1
|
||||
ports:
|
||||
- containerPort: 80
|
|
@ -4,16 +4,17 @@ import { extractPackageFile } from '.';
|
|||
const kubernetesImagesFile = Fixtures.get('kubernetes.yaml');
|
||||
const kubernetesConfigMapFile = Fixtures.get('configmap.yaml');
|
||||
const kubernetesArraySyntaxFile = Fixtures.get('array-syntax.yaml');
|
||||
const kubernetesRegistryAlias = Fixtures.get('kubernetes.registry-alias.yaml');
|
||||
const otherYamlFile = Fixtures.get('gitlab-ci.yaml');
|
||||
|
||||
describe('modules/manager/kubernetes/extract', () => {
|
||||
describe('extractPackageFile()', () => {
|
||||
it('returns null for empty', () => {
|
||||
expect(extractPackageFile('', 'file.yaml')).toBeNull();
|
||||
expect(extractPackageFile('', 'file.yaml', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('returns only API version', () => {
|
||||
const res = extractPackageFile(kubernetesConfigMapFile, 'file.yaml');
|
||||
const res = extractPackageFile(kubernetesConfigMapFile, 'file.yaml', {});
|
||||
expect(res?.deps).toStrictEqual([
|
||||
{
|
||||
currentValue: 'v1',
|
||||
|
@ -23,7 +24,7 @@ describe('modules/manager/kubernetes/extract', () => {
|
|||
});
|
||||
|
||||
it('extracts multiple Kubernetes configurations', () => {
|
||||
const res = extractPackageFile(kubernetesImagesFile, 'file.yaml');
|
||||
const res = extractPackageFile(kubernetesImagesFile, 'file.yaml', {});
|
||||
expect(res?.deps).toStrictEqual([
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
|
@ -55,7 +56,11 @@ describe('modules/manager/kubernetes/extract', () => {
|
|||
});
|
||||
|
||||
it('extracts image line in a YAML array', () => {
|
||||
const res = extractPackageFile(kubernetesArraySyntaxFile, 'file.yaml');
|
||||
const res = extractPackageFile(
|
||||
kubernetesArraySyntaxFile,
|
||||
'file.yaml',
|
||||
{}
|
||||
);
|
||||
expect(res?.deps).toStrictEqual([
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
|
@ -75,7 +80,7 @@ describe('modules/manager/kubernetes/extract', () => {
|
|||
});
|
||||
|
||||
it('ignores non-Kubernetes YAML files', () => {
|
||||
expect(extractPackageFile(otherYamlFile, 'file.yaml')).toBeNull();
|
||||
expect(extractPackageFile(otherYamlFile, 'file.yaml', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('handles invalid YAML files', () => {
|
||||
|
@ -83,7 +88,71 @@ describe('modules/manager/kubernetes/extract', () => {
|
|||
kind: ConfigMap
|
||||
<
|
||||
`;
|
||||
expect(extractPackageFile(invalidYaml, 'file.yaml')).toBeNull();
|
||||
expect(extractPackageFile(invalidYaml, 'file.yaml', {})).toBeNull();
|
||||
});
|
||||
|
||||
it('extracts images and replaces registries', () => {
|
||||
const res = extractPackageFile(kubernetesRegistryAlias, 'file.yaml', {
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
},
|
||||
});
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/node:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/node',
|
||||
replaceString: 'quay.io/node:0.0.1',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts images but does no replacement', () => {
|
||||
const res = extractPackageFile(kubernetesRegistryAlias, 'file.yaml', {
|
||||
registryAliases: {
|
||||
'index.docker.io': 'my-docker-mirror.registry.com',
|
||||
},
|
||||
});
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'{{depName}}{{#if newValue}}:{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'quay.io/node',
|
||||
replaceString: 'quay.io/node:0.0.1',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it('extracts images and does no double replacements', () => {
|
||||
const res = extractPackageFile(kubernetesRegistryAlias, 'file.yaml', {
|
||||
registryAliases: {
|
||||
'quay.io': 'my-quay-mirror.registry.com',
|
||||
'my-quay-mirror.registry.com': 'quay.io',
|
||||
},
|
||||
});
|
||||
expect(res).toEqual({
|
||||
deps: [
|
||||
{
|
||||
autoReplaceStringTemplate:
|
||||
'quay.io/node:{{#if newValue}}{{newValue}}{{/if}}{{#if newDigest}}@{{newDigest}}{{/if}}',
|
||||
currentDigest: undefined,
|
||||
currentValue: '0.0.1',
|
||||
datasource: 'docker',
|
||||
depName: 'my-quay-mirror.registry.com/node',
|
||||
replaceString: 'quay.io/node:0.0.1',
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -3,12 +3,13 @@ import { loadAll } from 'js-yaml';
|
|||
import { logger } from '../../../logger';
|
||||
import { newlineRegex, regEx } from '../../../util/regex';
|
||||
import { getDep } from '../dockerfile/extract';
|
||||
import type { PackageDependency, PackageFile } from '../types';
|
||||
import type { ExtractConfig, PackageDependency, PackageFile } from '../types';
|
||||
import type { KubernetesConfiguration } from './types';
|
||||
|
||||
export function extractPackageFile(
|
||||
content: string,
|
||||
fileName: string
|
||||
fileName: string,
|
||||
config: ExtractConfig
|
||||
): PackageFile | null {
|
||||
logger.trace('kubernetes.extractPackageFile()');
|
||||
|
||||
|
@ -20,21 +21,24 @@ export function extractPackageFile(
|
|||
}
|
||||
|
||||
const deps: PackageDependency[] = [
|
||||
...extractImages(content),
|
||||
...extractImages(content, config),
|
||||
...extractApis(content, fileName),
|
||||
];
|
||||
|
||||
return deps.length ? { deps } : null;
|
||||
}
|
||||
|
||||
function extractImages(content: string): PackageDependency[] {
|
||||
function extractImages(
|
||||
content: string,
|
||||
config: ExtractConfig
|
||||
): PackageDependency[] {
|
||||
const deps: PackageDependency[] = [];
|
||||
|
||||
for (const line of content.split(newlineRegex)) {
|
||||
const match = regEx(/^\s*-?\s*image:\s*'?"?([^\s'"]+)'?"?\s*$/).exec(line);
|
||||
if (match) {
|
||||
const currentFrom = match[1];
|
||||
const dep = getDep(currentFrom);
|
||||
const dep = getDep(currentFrom, true, config.registryAliases);
|
||||
logger.debug(
|
||||
{
|
||||
depName: dep.depName,
|
||||
|
|
Loading…
Reference in a new issue