From bdccf70d51543b1207cda94d100341aae70acf8d Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Luk=C3=A1=C5=A1=20Novotn=C3=BD?=
<33942303+dragonraid@users.noreply.github.com>
Date: Sat, 12 Dec 2020 10:41:55 +0100
Subject: [PATCH] Add support for hemfile (#1)
---
.dockeringnore | 7 ++
.gitignore | 3 +-
Dockerfile | 17 +++++
README.md | 53 ++++++++-----
action.yml | 3 +-
package.json | 8 +-
src/github.js | 4 +-
src/handlers.js | 56 ++++++++++++++
src/index.js | 112 ++++++++--------------------
src/{ => processors}/file.js | 45 +++--------
src/{ => processors}/file.test.js | 27 +++----
src/processors/helmfile.js | 79 ++++++++++++++++++++
src/processors/helmfile.test.js | 24 ++++++
src/{ => processors}/ubuntu.js | 56 +++++++-------
src/{ => processors}/ubuntu.test.js | 15 +++-
15 files changed, 321 insertions(+), 188 deletions(-)
create mode 100644 .dockeringnore
create mode 100644 Dockerfile
create mode 100644 src/handlers.js
rename src/{ => processors}/file.js (57%)
rename src/{ => processors}/file.test.js (73%)
create mode 100644 src/processors/helmfile.js
create mode 100644 src/processors/helmfile.test.js
rename src/{ => processors}/ubuntu.js (66%)
rename src/{ => processors}/ubuntu.test.js (77%)
diff --git a/.dockeringnore b/.dockeringnore
new file mode 100644
index 0000000..2899c6b
--- /dev/null
+++ b/.dockeringnore
@@ -0,0 +1,7 @@
+node_modules
+.env*
+action.yml
+LICENSE
+README.md
+.gitignore
+.eslintrc.yml
diff --git a/.gitignore b/.gitignore
index ad29183..6a0d87e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,2 @@
-test.sh
node_modules
-.env
+.env*
diff --git a/Dockerfile b/Dockerfile
new file mode 100644
index 0000000..daa44cd
--- /dev/null
+++ b/Dockerfile
@@ -0,0 +1,17 @@
+FROM node:14
+
+WORKDIR /app
+
+ARG HELMFILE_VERSION=v0.135.0
+
+ADD https://github.com/roboll/helmfile/releases/download/${HELMFILE_VERSION}/helmfile_linux_amd64 \
+ /tmp/
+
+COPY . .
+
+RUN npm install \
+ && mv /tmp/helmfile_linux_amd64 /usr/local/bin/helmfile \
+ && chmod +x /usr/local/bin/helmfile \
+ && curl https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
+
+ENTRYPOINT [ "node", "/app/src/index.js" ]
diff --git a/README.md b/README.md
index 507b276..3a9daee 100644
--- a/README.md
+++ b/README.md
@@ -7,10 +7,6 @@ It does so by reading specified file in your repository updating respective
dependency/version and opening pull request with this update to against default branch.
See _Types_ section to see, what can this action update.
-> NOTE: This action is not using standard github action execution with `uses` keyword, because that
-> would require to check in node_modules. Instead, it clones this action and then runs npm install
-> and npm start
-
## Inputs
Environment variables are used for inputs instead of actual github action inputs,
@@ -55,7 +51,7 @@ By default this type returns latest image based on your inputs:
| INSTANCE_TYPE | Virtualization details, varies based on cloud | `hvm-ssd` | no |
| RELEASE | release (do not supply if you want latest) | `20200924` | no |
-## Example
+#### Example
```yaml
name: update ubuntu base image
@@ -68,17 +64,11 @@ jobs:
update:
runs-on: ubuntu-20.04
steps:
- - name: checkout dragonraid/deployment-bumper
- uses: actions/checkout@v2
- with:
- repository: dragonraid/deployment-bumper
- ref: refs/heads/main
- path: ./.github/actions/deployment-bumper
- - name: run deployment-bumper
- working-directory: ./.github/actions/deployment-bumper
+ - name: update ubuntu AMI
+ uses: dragonraid/deployment-bumper
env:
TYPE: ubuntu
- FILE: packer.json
+ FILE: ami.json
REPOSITORY: dragonraid/test
USERNAME: ${{ secrets.username }}
PASSWORD: ${{ secrets.password }}
@@ -88,7 +78,36 @@ jobs:
VERSION: '20.04'
ARCHITECTURE: amd64
INSTANCE_TYPE: hvm-ssd
- run: |
- npm install --only=prod
- npm start
+```
+
+### Helmfile lock
+
+With this type you can update [helmfile](https://github.com/roboll/helmfile) lock files.
+Under the hood this type runs [helmfile deps](https://github.com/roboll/helmfile#deps) command.
+
+| Input | Description | Example | Required |
+| :---------- | --------------------------------------: | ------: | -------: |
+| ENVIRONMENT | helmfile global options `--environment` | `myEnv` | no |
+
+#### Example
+
+```yaml
+name: update helmfile lock
+
+on:
+ schedule:
+ - cron: '0 0 1 * *'
+
+jobs:
+ update:
+ runs-on: ubuntu-20.04
+ steps:
+ - name: update helmfile.lock
+ uses: dragonraid/deployment-bumper
+ env:
+ TYPE: helmfile
+ FILE: helmfile.yaml
+ USERNAME: ${{ secrets.username }}
+ PASSWORD: ${{ secrets.password }}
+ ENVIRONMENT: staging
```
diff --git a/action.yml b/action.yml
index ccae8c1..6f4fad3 100644
--- a/action.yml
+++ b/action.yml
@@ -1,7 +1,8 @@
name: 'Deployment Bumper'
description: 'Update deployment related stuff'
runs:
- using: 'node12'
+ using: 'docker'
+ image: 'Dockerfile'
branding:
icon: 'edit'
color: blue
diff --git a/package.json b/package.json
index e131158..4df4b64 100644
--- a/package.json
+++ b/package.json
@@ -5,9 +5,11 @@
"main": "src/index.js",
"scripts": {
"cleanup": "rm -fr /tmp/dragonraid",
- "dev": "npm run cleanup && node src/index.js",
- "start": "NODE_ENV=production node src/index.js",
- "test": "jest ."
+ "dev-ubuntu": "npm run cleanup && DOTENV_CONFIG_PATH='./.envUbuntu' node -r dotenv/config src/index.js",
+ "dev-helmfile": "npm run cleanup && DOTENV_CONFIG_PATH='./.envHelmfile' node -r dotenv/config src/index.js",
+ "start": "node src/index.js",
+ "test": "jest .",
+ "lint": "eslint ."
},
"author": {
"name": "Lukas Novotny",
diff --git a/src/github.js b/src/github.js
index fdb9f48..31eb498 100644
--- a/src/github.js
+++ b/src/github.js
@@ -14,14 +14,14 @@ class Repository {
* @param {string} username - github username
* @param {string} password - github personal access token
* @param {string} path - where to clone repository
- * @param {string} branchNamePrefix - branch name prefix
+ * @param {string} branchName - branch name prefix
* @param {string} pathPrefix - local repository path prefix
*/
constructor({
repository,
+ username,
password,
path,
- username,
branchName,
pathPrefix = '/tmp/',
}) {
diff --git a/src/handlers.js b/src/handlers.js
new file mode 100644
index 0000000..ebd730f
--- /dev/null
+++ b/src/handlers.js
@@ -0,0 +1,56 @@
+const { Helmfile } = require('./processors/helmfile');
+const { Ubuntu } = require('./processors/ubuntu');
+
+/**
+ * Ubuntu processor handler. Edits specified value in specified file
+ * based on input parameters
+ * @param {object} filePath - full path to file
+ */
+const handleUbuntu = async (filePath) => {
+ const filterValues = {
+ cloud: process.env.CLOUD || null,
+ zone: process.env.ZONE || null,
+ version: process.env.VERSION || null,
+ architecture: process.env.ARCHITECTURE || null,
+ instanceType: process.env.INSTANCE_TYPE || null,
+ release: process.env.RELEASE || null,
+ };
+
+ const rawKeys = process.env.KEYS;
+ let keys;
+ if (rawKeys) {
+ keys = rawKeys.split(',');
+ } else {
+ throw new Error('KEYS must be supplied!');
+ }
+
+ const filter = {};
+ Object.keys(filterValues).forEach((value) => {
+ if (filterValues[value]) filter[value] = filterValues[value];
+ });
+ const ubuntu = new Ubuntu(filter, filePath, keys);
+ await ubuntu.run();
+ console.log(`File "${filePath}" has been successfully updated.`);
+};
+
+/**
+ * Helmfile processor handler. Updates helmfiles lock file.
+ * @param {object} filePath - full path to file
+ */
+const handleHelmfile = async (filePath) => {
+ const helmfileArgs = {
+ file: filePath,
+ };
+ if (process.env.ENVIRONMENT) {
+ helmfileArgs.environment = process.env.ENVIRONMENT;
+ }
+
+ const helmfile = new Helmfile(helmfileArgs);
+ await helmfile.run();
+ console.log(`File "${filePath}" has been successfully updated.`);
+};
+
+module.exports = {
+ handleUbuntu,
+ handleHelmfile,
+};
diff --git a/src/index.js b/src/index.js
index 6668531..cb5d2ca 100644
--- a/src/index.js
+++ b/src/index.js
@@ -1,17 +1,12 @@
-const { File } = require('./file');
const { Repository } = require('./github');
-const { Ubuntu } = require('./ubuntu');
+const handlers = require('./handlers');
-// load environment variables from .env file if not running in production
-if (process.env.NODE_ENV !== 'production') {
- require('dotenv').config();
-}
-
-// Check if environment variable exists, otherwise set default
+/**
+ * Raw configuration.
+ */
const RAW_CONFIG = {
TYPE: process.env.TYPE || null,
FILE: process.env.FILE || null,
- KEYS: process.env.KEYS || null,
BRANCH_NAME: process.env.BRANCH_NAME || process.env.TYPE,
BRANCH_PREFIX: process.env.BRANCH_PREFIX || 'update',
REPOSITORY: process.env.REPOSITORY || process.env.GITHUB_REPOSITORY,
@@ -30,45 +25,22 @@ const CONFIG = {};
const processConfig = () => {
for (const [key, value] of Object.entries(RAW_CONFIG)) {
if (!value) {
- if (value === 'USERNAME' || value === 'PASSWORD') continue;
+ if (key === 'USERNAME' || key === 'PASSWORD') {
+ throw new Error(`Invalid USERNAME or PASSWORD!`);
+ };
throw new Error(
`Invalid configuration value: ${value} for ${key}.`,
);
}
- switch (key) {
- case 'KEYS':
- CONFIG[key] = value.split(',');
- break;
- default:
- CONFIG[key] = value;
- }
+ CONFIG[key] = value;
}
};
-const handleUbuntu = async () => {
- const filterValues = {
- cloud: process.env.CLOUD || null,
- zone: process.env.ZONE || null,
- version: process.env.VERSION || null,
- architecture: process.env.ARCHITECTURE || null,
- instanceType: process.env.INSTANCE_TYPE || null,
- release: process.env.RELEASE || null,
- };
-
- const filter = {};
- Object.keys(filterValues).forEach((value) => {
- if (filterValues[value]) filter[value] = filterValues[value];
- });
- const ubuntu = new Ubuntu(filter);
- const latestUbuntu = await ubuntu.latest;
- const keyValuePairs = {};
- CONFIG.KEYS.forEach((key) => {
- keyValuePairs[key] = latestUbuntu.id;
- });
-
- return keyValuePairs;
-};
-
+/**
+ * Clone repository and checkout the feature branch
+ * @param {string} branchName - feature branch name
+ * @return {object}
+ */
const initializeRepo = async (branchName) => {
const repository = new Repository({
repository: CONFIG.REPOSITORY,
@@ -81,57 +53,37 @@ const initializeRepo = async (branchName) => {
return repository;
};
-const throwError = (resolved) => {
- resolved.forEach((process) => {
- if (process.status === 'rejected') {
- console.error('An error has occurred.');
- throw new Error(JSON.stringify(process.reason));
- }
- });
-};
-
-const TYPE_PROCESSORS = {
- ubuntu: handleUbuntu,
+/**
+ * Define handle types
+ */
+const PROCESSOR_TYPES = {
+ ubuntu: handlers.handleUbuntu,
+ helmfile: handlers.handleHelmfile,
};
-const main = async () => {
+/**
+ * Main function
+ */
+(async () => {
try {
processConfig();
} catch (err) {
console.error('Config processor has failed!', err);
process.exit(1);
}
- const processor = await Promise.allSettled([
- TYPE_PROCESSORS[CONFIG.TYPE](),
- // TODO: option for supplying custom branch name and custom prefix
- initializeRepo(`${CONFIG.BRANCH_PREFIX}/${CONFIG.BRANCH_NAME}`),
- ]);
- throwError(processor);
- console.log(`Successfully executed processor ${CONFIG.TYPE}.`);
-
- const repository = processor[1].value;
- const filePath = `${repository.path}/${CONFIG.FILE}`;
- const keyValuePairs = processor[0].value;
-
- try {
- const file = new File({ filePath, keyValuePairs });
- await file.run();
- } catch (err) {
- console.error('Updating file has failed!', err);
- process.exit(1);
- }
- console.log(`File "${filePath}" has been successfully updated.`);
try {
+ const repository = await initializeRepo(
+ `${CONFIG.BRANCH_PREFIX}/${CONFIG.BRANCH_NAME}`,
+ );
+ const fullFilePath = `${repository.path}/${CONFIG.FILE}`;
+ await PROCESSOR_TYPES[CONFIG.TYPE](fullFilePath);
+ console.log(`Successfully executed processor ${CONFIG.TYPE}.`);
await repository.push(`update ${CONFIG.TYPE}`);
await repository.createPullRequest();
+ console.log('Pull-request created.');
} catch (err) {
- console.error(`Opening pull request with changes has failed!`, err);
+ console.error(`${CONFIG.TYPE} processor failed.`, err);
process.exit(1);
}
- console.log(
- `Successfully pushed branch "${repository.branchName}" to remote.`,
- );
-};
-
-main();
+})();
diff --git a/src/file.js b/src/processors/file.js
similarity index 57%
rename from src/file.js
rename to src/processors/file.js
index eb6a20a..7178e03 100644
--- a/src/file.js
+++ b/src/processors/file.js
@@ -24,50 +24,26 @@ const FILE_TYPE_PROCESSORS = {
*/
class File {
/**
- * @param {string} file - file to be edited
- * @param {object} keyValuePairs - key-value pairs to be edited
+ * @param {string} filePath - file to be edited
*/
- constructor({
- filePath,
- keyValuePairs,
- }) {
+ constructor(filePath) {
this.filePath = null;
- this.keyValuePairs = null;
this.type = null;
- this.init(filePath, keyValuePairs);
+ this.init(filePath);
}
/**
* Initiates properties by parsing descriptor
* @param {string} filePath - file to be edited
- * @param {object} keyValuePairs - key-value pairs to be edited
*/
- init(filePath, keyValuePairs) {
+ init(filePath) {
+ if (!filePath) {
+ throw new Error('filePath cannot be empty!');
+ }
const fileSplit = filePath.split('.');
const fileType = fileSplit[fileSplit.length - 1];
this.filePath = filePath;
this.type = FILE_TYPES[fileType.toLocaleLowerCase()];
-
- if (typeof keyValuePairs !== 'object') {
- throw new Error(
- `"keyValuePairs" must be an object. Got ${keyValuePairs}`,
- );
- }
- // TODO: add validation for key value
- this.keyValuePairs = keyValuePairs;
- }
-
-
- /**
- * Run main logic
- * @param {string} value - value of specified key will be changed
- * TODO: implement multiple values for multiple keys
- */
- async run() {
- const data = await this.read();
- const editedData = this.edit(data);
- await this.write(editedData);
- // if changed write, else do nothing
}
/**
@@ -90,11 +66,12 @@ class File {
/**
* Edit file data and return edited data
- * @param {object} data - parsed file data
+ * @param {object} data - parsed file data
+ * @param {object} keyValuePairs - key-values pair that edits data
* @return {object}
*/
- edit(data) {
- for (const [key, value] of Object.entries(this.keyValuePairs)) {
+ edit(data, keyValuePairs) {
+ for (const [key, value] of Object.entries(keyValuePairs)) {
_.set(data, key, value);
}
return data;
diff --git a/src/file.test.js b/src/processors/file.test.js
similarity index 73%
rename from src/file.test.js
rename to src/processors/file.test.js
index a142f69..943c04a 100644
--- a/src/file.test.js
+++ b/src/processors/file.test.js
@@ -2,7 +2,6 @@ const { File } = require('./file');
const fs = require('fs').promises;
const yaml = require('js-yaml');
-
const filePathJson = './test_file.JSON';
const filePathYaml = './test_file.yaml';
const keyValuePairs = {
@@ -17,8 +16,14 @@ const resultedFileData = {
keyN: 'valueN',
};
-const jsonFile = new File({ filePath: filePathJson, keyValuePairs });
-const yamlFile = new File({ filePath: filePathYaml, keyValuePairs });
+const jsonFile = new File(filePathJson);
+const yamlFile = new File(filePathYaml);
+
+describe('File', () => {
+ test('throws an error if not properly initialized', () => {
+ expect(() => new File()).toThrow();
+ });
+});
describe('JSON file', () => {
beforeEach(async () => {
@@ -45,13 +50,6 @@ describe('JSON file', () => {
const data = JSON.parse(content);
expect(data).toMatchObject(resultedFileData);
});
-
- test('is able to execute run() function', async () => {
- await jsonFile.run();
- const content = await fs.readFile(filePathJson, 'utf8');
- const data = JSON.parse(content);
- expect(data).toMatchObject(resultedFileData);
- });
});
describe('YAML file', () => {
@@ -79,18 +77,11 @@ describe('YAML file', () => {
const data = yaml.safeLoad(content);
expect(data).toMatchObject(resultedFileData);
});
-
- test('is able to execute run() function', async () => {
- await yamlFile.run();
- const content = await fs.readFile(filePathYaml, 'utf8');
- const data = yaml.safeLoad(content);
- expect(data).toMatchObject(resultedFileData);
- });
});
describe('File', () => {
test('can be edited', () => {
- const editedData = jsonFile.edit(origFileData);
+ const editedData = jsonFile.edit(origFileData, keyValuePairs);
expect(editedData).toMatchObject(resultedFileData);
});
});
diff --git a/src/processors/helmfile.js b/src/processors/helmfile.js
new file mode 100644
index 0000000..e7bda69
--- /dev/null
+++ b/src/processors/helmfile.js
@@ -0,0 +1,79 @@
+const util = require('util');
+const exec = util.promisify(require('child_process').exec);
+
+const HELMFILE_BIN_PATH = '/usr/local/bin/helmfile';
+const HELMFILE_DEPS_COMMAND = 'deps';
+
+const GLOBAL_ARGUMENTS = {
+ file: '-f',
+ environment: '-e',
+};
+
+/**
+ * Process helmfile https://github.com/roboll/helmfile
+ */
+class Helmfile {
+ /**
+ * Runs helmfile deps command to update chart dependencies
+ * @param {object} globalArgs - global arguments
+ */
+ constructor(globalArgs) {
+ this.helmfile = HELMFILE_BIN_PATH;
+ this.globalArgs = null;
+ this.init(globalArgs);
+ }
+
+ /**
+ * Constructs global arguments of helmfile
+ * @param {array} args - arguments i.e [{key1: val1},.. {keyN: valN}]
+ */
+ init(args) {
+ let argString = '';
+ const globalArgsKeys = Object.keys(GLOBAL_ARGUMENTS);
+ const argKeys = Object.keys(args);
+ argKeys.forEach((argKey) => {
+ if (globalArgsKeys.includes(argKey)) {
+ const fullArg = `${GLOBAL_ARGUMENTS[argKey]} ${args[argKey]} `;
+ argString = argString.concat(fullArg);
+ } else {
+ console.log(`Helmfile: unknown global argument ${argKey}`);
+ }
+ });
+ this.globalArgs = argString.trim();
+ }
+
+ /**
+ * Execute helmfile command with args
+ * @param {string} args - command argument
+ * @return {object}
+ */
+ async execute(args) {
+ const command = `${this.helmfile} ${this.globalArgs} ${args}`;
+ let stdout;
+ let stderr;
+ try {
+ ({ stdout, stderr } = await exec(command));
+ } catch (err) {
+ console.error('Helmfile execute exits with an error', err);
+ throw err;
+ };
+
+ return { stdout, stderr };
+ }
+
+ /**
+ * Runs helmfile deps command to update dependencies.
+ */
+ async run() {
+ const { stdout, stderr } = await this.execute(HELMFILE_DEPS_COMMAND);
+ if (stderr) {
+ // eslint-disable-next-line max-len
+ console.log(`helmfile ${HELMFILE_DEPS_COMMAND} stderr:\n ${stderr}`);
+ }
+ console.log(`helmfile ${HELMFILE_DEPS_COMMAND} stdout:\n ${stdout}`);
+ }
+}
+
+module.exports = {
+ Helmfile,
+};
diff --git a/src/processors/helmfile.test.js b/src/processors/helmfile.test.js
new file mode 100644
index 0000000..804a872
--- /dev/null
+++ b/src/processors/helmfile.test.js
@@ -0,0 +1,24 @@
+const { Helmfile } = require('./helmfile');
+
+describe('Helmfile can', () => {
+ test('construct global arguments', () => {
+ const globalArgsInput = {
+ file: '/tmp/helmfile.yaml',
+ environment: 'default',
+ };
+ const globalArgsOutput = '-f /tmp/helmfile.yaml -e default';
+ const helmfile = new Helmfile(globalArgsInput);
+ expect(helmfile.globalArgs).toBe(globalArgsOutput);
+ });
+
+ test('construct only global arguments', () => {
+ const globalArgsInput = {
+ file: '/tmp/helmfile.yaml',
+ environment: 'default',
+ foo: 'bar',
+ };
+ const globalArgsOutput = '-f /tmp/helmfile.yaml -e default';
+ const helmfile = new Helmfile(globalArgsInput);
+ expect(helmfile.globalArgs).toBe(globalArgsOutput);
+ });
+});
diff --git a/src/ubuntu.js b/src/processors/ubuntu.js
similarity index 66%
rename from src/ubuntu.js
rename to src/processors/ubuntu.js
index e809b89..1dbbafd 100644
--- a/src/ubuntu.js
+++ b/src/processors/ubuntu.js
@@ -1,4 +1,5 @@
const axios = require('axios');
+const { File } = require('./file');
const UBUNTU_IMAGE_FINDER_URL = 'https://cloud-images.ubuntu.com/locator/releasesTable?_=1598175887311';
const FIELD_MAPPINGS = {
@@ -16,42 +17,30 @@ const LINK_REGEX = /(.*\")(.*)(\">)(.*)(<.*)/;
/**
* Linux ubuntu handler
*/
-class Ubuntu {
+class Ubuntu extends File {
/**
* Represents ubuntu image
- * @param {string} criteria - object with filter properties
- * example: {
- * cloud: 'Amazon AWS',
- * zone: 'us-east-1',
- * name: 'bionic',
- * version: '18.04',
- * architecture: 'amd64',
- * instanceType: 'hvm-ssd',
- * release: '20201204'
- * }
+ * @param {object} criteria - object with filter properties. For example:
+ * {
+ * cloud: 'Amazon AWS',
+ * zone: 'us-east-1',
+ * name: 'bionic',
+ * version: '18.04',
+ * architecture: 'amd64',
+ * instanceType: 'hvm-ssd',
+ * release: '20201204'
+ * }
+ * @param {string} filePath - path to file
+ * @param {array} keys - string keys to be replaced
*/
- constructor(criteria) {
+ constructor(criteria, filePath, keys) {
+ super(filePath);
this.criteria = criteria;
+ this.keys = keys;
this.allImages = null;
this.processedImages = null;
}
- /**
- * Gets latest image.
- */
- get latest() {
- if (!this.processedImages) {
- // Workaround since you cannot have async getter
- return (async () => {
- await this.run();
- })().then(() => {
- return this._constructImageProperties(this.processedImages[0]);
- });
- } else {
- return this.processedImages[0];
- }
- }
-
/**
* Gets images from UBUNTU_IMAGE_FINDER_URL and makes them parsable
*/
@@ -78,6 +67,7 @@ class Ubuntu {
);
});
+ images = images.map(this._constructImageProperties);
this.processedImages = images.sort(
(a, b) => (
// eslint-disable-next-line max-len
@@ -105,11 +95,19 @@ class Ubuntu {
}
/**
- * Runs ubuntu image retrieval
+ * Runs, initializes and edits file
*/
async run() {
await this.getImages();
this.filterImages();
+ const latest = this.processedImages[0];
+ const keyValuePairs = {};
+ this.keys.forEach((key) => {
+ keyValuePairs[key] = latest.id;
+ });
+ const data = await this.read();
+ const editedData = this.edit(data, keyValuePairs);
+ await this.write(editedData);
}
}
diff --git a/src/ubuntu.test.js b/src/processors/ubuntu.test.js
similarity index 77%
rename from src/ubuntu.test.js
rename to src/processors/ubuntu.test.js
index e51d806..5153658 100644
--- a/src/ubuntu.test.js
+++ b/src/processors/ubuntu.test.js
@@ -1,7 +1,11 @@
const axios = require('axios');
+const fs = require('fs');
const { Ubuntu } = require('./ubuntu');
jest.mock('axios');
+jest.mock('fs', () => ({
+ promises: {},
+}));
describe('Ubuntu can', () => {
test('determine latest image', async () => {
@@ -17,6 +21,8 @@ describe('Ubuntu can', () => {
["Amazon AWS", "sa-east-1", "focal", "20.04", "amd64", "hvm-ssd", "20190907", "ami-0f4c19e1a758f4efe"],
["Amazon AWS", "us-west-2", "focal", "18.04", "amd64", "hvm-ssd", "20200907", "ami-0f4c19e1a758f4eff"],]}`,
};
+ const fileContent = 'foo: ami-xxxxx';
+ const filePath = 'foo.yaml';
const expected = {
cloud: 'Amazon AWS',
zone: 'sa-east-1',
@@ -30,8 +36,13 @@ describe('Ubuntu can', () => {
};
axios.get.mockResolvedValue(axiosResponse);
- const ubuntu = new Ubuntu(criteria);
- expect(await ubuntu.latest).toMatchObject(expected);
+ fs.promises.readFile = jest.fn().mockResolvedValue(
+ Buffer.from(fileContent),
+ );
+ fs.promises.writeFile = jest.fn().mockImplementation();
+ const ubuntu = new Ubuntu(criteria, filePath, ['foo']);
+ await ubuntu.run();
+ expect(ubuntu.processedImages[0]).toMatchObject(expected);
// TODO: add tests for other providers
});
});