From c07bf5fc55be7683ac4b72973fb81ffee36b524e Mon Sep 17 00:00:00 2001 From: Charles Korn <charleskorn@users.noreply.github.com> Date: Wed, 9 Dec 2020 19:16:16 +1100 Subject: [PATCH] feat: batect manager (#7898) Co-authored-by: HonkingGoose <34918129+HonkingGoose@users.noreply.github.com> Co-authored-by: Michael Kriese <michael.kriese@visualon.de> Co-authored-by: Rhys Arkins <rhys@arkins.net> --- lib/manager/batect/__fixtures__/batect.yml | 15 ++++++ lib/manager/batect/extract.spec.ts | 41 +++++++++++++++ lib/manager/batect/extract.ts | 59 ++++++++++++++++++++++ lib/manager/batect/index.ts | 7 +++ lib/manager/batect/readme.md | 23 +++++++++ lib/manager/batect/types.ts | 7 +++ 6 files changed, 152 insertions(+) create mode 100644 lib/manager/batect/__fixtures__/batect.yml create mode 100644 lib/manager/batect/extract.spec.ts create mode 100644 lib/manager/batect/extract.ts create mode 100644 lib/manager/batect/index.ts create mode 100644 lib/manager/batect/readme.md create mode 100644 lib/manager/batect/types.ts diff --git a/lib/manager/batect/__fixtures__/batect.yml b/lib/manager/batect/__fixtures__/batect.yml new file mode 100644 index 0000000000..d8fb1ac817 --- /dev/null +++ b/lib/manager/batect/__fixtures__/batect.yml @@ -0,0 +1,15 @@ +containers: + container-1: + image: alpine:1.2.3 + + container-2: + image: alpine:1.2.3 + + container-3: + image: ubuntu:20.04 + + container-4: + build_directory: some_build_directory + + container-5: + image: postgres:9.6.20@sha256:166179811e4c75f8a092367afed6091208c8ecf60b111c7e49f29af45ca05e08 diff --git a/lib/manager/batect/extract.spec.ts b/lib/manager/batect/extract.spec.ts new file mode 100644 index 0000000000..abd36560a1 --- /dev/null +++ b/lib/manager/batect/extract.spec.ts @@ -0,0 +1,41 @@ +import { readFileSync } from 'fs'; +import { getDep } from '../dockerfile/extract'; +import { extractPackageFile } from './extract'; + +const sampleFile = readFileSync( + 'lib/manager/batect/__fixtures__/batect.yml', + 'utf8' +); + +describe('lib/manager/batect/extract', () => { + describe('extractPackageFile()', () => { + it('returns null for empty configuration file', () => { + expect(extractPackageFile('')).toBeNull(); + }); + + it('returns null for non-object configuration file', () => { + expect(extractPackageFile('nothing here')).toBeNull(); + }); + + it('returns null for malformed configuration file', () => { + expect(extractPackageFile('nothing here\n:::::::')).toBeNull(); + }); + + it('returns null for configuration file without containers', () => { + expect(extractPackageFile('something_else: some_value')).toBeNull(); + }); + + it('extracts all available images from a valid Batect configuration file', () => { + const res = extractPackageFile(sampleFile); + + expect(res.deps).toEqual([ + getDep('alpine:1.2.3'), + getDep('alpine:1.2.3'), + getDep('ubuntu:20.04'), + getDep( + 'postgres:9.6.20@sha256:166179811e4c75f8a092367afed6091208c8ecf60b111c7e49f29af45ca05e08' + ), + ]); + }); + }); +}); diff --git a/lib/manager/batect/extract.ts b/lib/manager/batect/extract.ts new file mode 100644 index 0000000000..3846a9008b --- /dev/null +++ b/lib/manager/batect/extract.ts @@ -0,0 +1,59 @@ +import { safeLoad } from 'js-yaml'; + +import { logger } from '../../logger'; +import { PackageFile } from '../common'; +import { getDep } from '../dockerfile/extract'; +import { BatectConfig } from './types'; + +function loadConfig(content: string): BatectConfig { + const config = safeLoad(content); + + if (typeof config !== 'object') { + throw new Error( + `Configuration file does not contain a YAML object (it is ${typeof config}).` + ); + } + + return config as BatectConfig; +} + +function extractImages(config: BatectConfig): string[] { + if (config.containers === undefined) { + return []; + } + + return Object.values(config.containers) + .filter((container) => container.image !== undefined) + .map((container) => container.image); +} + +export function extractPackageFile( + content: string, + fileName?: string +): PackageFile | null { + logger.debug('batect.extractPackageFile()'); + + try { + const config = loadConfig(content); + const images = extractImages(config); + const deps = images.map((image) => getDep(image)); + + if (deps.length === 0) { + return null; + } + + logger.trace( + { deps, fileName }, + 'Loaded images from Batect configuration file' + ); + + return { deps }; + } catch (err) { + logger.warn( + { err, fileName }, + 'Extracting dependencies from Batect configuration file failed' + ); + + return null; + } +} diff --git a/lib/manager/batect/index.ts b/lib/manager/batect/index.ts new file mode 100644 index 0000000000..78ace05e28 --- /dev/null +++ b/lib/manager/batect/index.ts @@ -0,0 +1,7 @@ +import { extractPackageFile } from './extract'; + +export { extractPackageFile }; + +export const defaultConfig = { + fileMatch: ['(^|/)batect(-bundle)?\\.yml$'], +}; diff --git a/lib/manager/batect/readme.md b/lib/manager/batect/readme.md new file mode 100644 index 0000000000..980e2bd926 --- /dev/null +++ b/lib/manager/batect/readme.md @@ -0,0 +1,23 @@ +Extracts all Docker images from Batect configuration files. + +By default, the manager searches for files called `batect.yml` or `batect-bundle.yml`. + +If you keep your Batect configuration in other files, you'll need to tell Renovate where to find them. +This includes files included into your main configuration file with `include`. + +You do this by creating a `"batect"` object in your `renovate.json` file. +This object should contain a `fileMatch` array with regular expressions that match the configuration file names. + +For example: + +```json +{ + "batect": { + "fileMatch": [ + "(^|/)batect(-bundle)?\\.yml$", + "(^|/)my-other-batect-file\\.yml$", + "^a-directory/[^/]*\\.yml$" + ] + } +} +``` diff --git a/lib/manager/batect/types.ts b/lib/manager/batect/types.ts new file mode 100644 index 0000000000..b62adbc14f --- /dev/null +++ b/lib/manager/batect/types.ts @@ -0,0 +1,7 @@ +export interface BatectConfig { + containers?: Record<string, BatectContainer>; +} + +export interface BatectContainer { + image?: string; +} -- GitLab