Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions workspace/packages/muse-core/lib/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ var originalRequire = Module.prototype.require;

// Ensure @ebay/muse-core only has one instance
const __museCoreSingleton = module.exports;
Module.prototype.require = function() {
Module.prototype.require = function () {
if (arguments[0] === '@ebay/muse-core') return __museCoreSingleton;
return originalRequire.apply(this, arguments);
};
Expand All @@ -18,7 +18,7 @@ const plugin = require('js-plugin');
const envFile1 = path.join(process.cwd(), '.muse.env');
const envFile2 = path.join(os.homedir(), '.muse.env');

[envFile1, envFile2].some(envFile => {
[envFile1, envFile2].some((envFile) => {
if (fs.existsSync(envFile)) {
require('dotenv').config({ path: envFile });
return true;
Expand All @@ -29,7 +29,7 @@ const config = require('./config');

module.exports.config = config;
module.exports.logger = require('./logger');
module.exports.registerPlugin = p => {
module.exports.registerPlugin = (p) => {
if (config.__pluginLoaded) {
throw new Error(
`You can only register a plugin before initialization. Usually you should register a plugin in the global scope in your code.`,
Expand All @@ -47,6 +47,7 @@ module.exports.pm = require('./pm');
module.exports.req = require('./req');
module.exports.data = require('./data');
module.exports.storage = require('./storage');
module.exports.msp = require('./msp');
module.exports.utils = require('./utils');
module.exports.plugin = plugin;

Expand Down
51 changes: 51 additions & 0 deletions workspace/packages/muse-core/lib/msp/addPreset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
const { asyncInvoke, osUsername, validate } = require('../utils');
const { registry } = require('../storage');
const getMsp = require('./getMsp');
const schema = require('../schemas/msp/addPreset.json');
const logger = require('../logger').createLogger('muse.msp.addPreset');

/**
* @module muse-core/msp/addPreset
*/

/**
* @description Add a new preset to /msp.yaml.
* @param {object} params
* @param {string} params.name The preset name.
* @param {object} params.preset The preset object.
* @param {string} [params.preset.extends] Parent preset name.
* @param {object} [params.preset.versions] Package versions for this preset.
* @param {string} [params.author=osUsername]
* @param {string} [params.msg] Commit message.
* @returns {object} The created preset.
*/
module.exports = async (params = {}) => {
validate(schema, params);
const ctx = {};
if (!params.author) params.author = osUsername;
const { name, preset, author, msg } = params;
logger.info(`Adding preset ${name}...`);
await asyncInvoke('museCore.msp.beforeAddPreset', ctx, params);

let msp = await getMsp();
if (!msp) msp = {};
if (msp[name]) throw new Error(`Preset ${name} already exists.`);

ctx.preset = {
creation: new Date().toJSON(),
...preset,
};

try {
msp[name] = ctx.preset;
await asyncInvoke('museCore.msp.addPreset', ctx, params);
await registry.setYaml('/msp.yaml', msp, msg || `Add preset ${name} by ${author}`);
} catch (err) {
ctx.error = err;
await asyncInvoke('museCore.msp.failedAddPreset', ctx, params);
throw err;
}
await asyncInvoke('museCore.msp.afterAddPreset', ctx, params);
logger.info(`Add preset success: ${name}.`);
return ctx.preset;
};
89 changes: 89 additions & 0 deletions workspace/packages/muse-core/lib/msp/addPreset.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
const { vol } = require('memfs');
const plugin = require('js-plugin');
const muse = require('../');
const { registry } = require('../storage');

const testJsPlugin = {
name: 'test-addPreset',
museCore: {
msp: {
addPreset: jest.fn(),
beforeAddPreset: jest.fn(),
afterAddPreset: jest.fn(),
},
},
};
plugin.register(testJsPlugin);

describe('addPreset tests.', () => {
beforeEach(() => {
vol.reset();
});

it('should create msp.yaml and add preset when file does not exist', async () => {
const preset = await muse.msp.addPreset({
name: 'default',
preset: { versions: { '@ebay/muse-core': '1.0.45' } },
author: 'nate',
});

expect(preset).toMatchObject({ versions: { '@ebay/muse-core': '1.0.45' } });
expect(preset.creation).toBeDefined();

const msp = await registry.getJsonByYaml('/msp.yaml');
expect(msp.default).toMatchObject({ versions: { '@ebay/muse-core': '1.0.45' } });

expect(testJsPlugin.museCore.msp.addPreset).toBeCalledTimes(1);
expect(testJsPlugin.museCore.msp.beforeAddPreset).toBeCalledTimes(1);
expect(testJsPlugin.museCore.msp.afterAddPreset).toBeCalledTimes(1);
});

it('should add preset to existing msp.yaml', async () => {
await registry.set('/msp.yaml', 'default:\n versions:\n "@ebay/muse-core": "1.0.45"\n');

await muse.msp.addPreset({
name: 'muse-react',
preset: { extends: 'default', versions: { '@ebay/muse-lib-react': '2.0.3' } },
author: 'nate',
});

const msp = await registry.getJsonByYaml('/msp.yaml');
expect(Object.keys(msp)).toEqual(['default', 'muse-react']);
expect(msp['muse-react'].extends).toBe('default');
});

it('should throw if preset already exists', async () => {
await registry.set('/msp.yaml', 'default:\n versions: {}\n');

try {
await muse.msp.addPreset({ name: 'default', preset: {}, author: 'nate' });
expect(true).toBe(false);
} catch (err) {
expect(err.message).toMatch('already exists');
}
});

it('should throw and invoke failedAddPreset on error', async () => {
const testJsPluginFails = {
name: 'test-addPreset-fail',
museCore: {
msp: {
addPreset: jest.fn().mockRejectedValue(new Error('storage error')),
beforeAddPreset: jest.fn(),
afterAddPreset: jest.fn(),
failedAddPreset: jest.fn(),
},
},
};
plugin.register(testJsPluginFails);

try {
await muse.msp.addPreset({ name: 'new-preset', preset: {}, author: 'nate' });
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('storage error');
}
expect(testJsPluginFails.museCore.msp.failedAddPreset).toBeCalledTimes(1);
expect(testJsPluginFails.museCore.msp.afterAddPreset).toBeCalledTimes(0);
});
});
44 changes: 44 additions & 0 deletions workspace/packages/muse-core/lib/msp/deletePreset.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
const { asyncInvoke, osUsername, validate } = require('../utils');
const { registry } = require('../storage');
const getMsp = require('./getMsp');
const schema = require('../schemas/msp/deletePreset.json');
const logger = require('../logger').createLogger('muse.msp.deletePreset');

/**
* @module muse-core/msp/deletePreset
*/

/**
* @description Delete a preset from /msp.yaml.
* @param {object} params
* @param {string} params.name The preset name to delete.
* @param {string} [params.author=osUsername]
* @param {string} [params.msg] Commit message.
*/
module.exports = async (params = {}) => {
validate(schema, params);
const ctx = {};
if (!params.author) params.author = osUsername;
const { name, author, msg } = params;
logger.info(`Deleting preset ${name}...`);
await asyncInvoke('museCore.msp.beforeDeletePreset', ctx, params);

const msp = await getMsp();
if (!msp) throw new Error('msp.yaml does not exist.');
if (!msp[name]) throw new Error(`Preset ${name} does not exist.`);

ctx.preset = msp[name];

try {
delete msp[name];
await asyncInvoke('museCore.msp.deletePreset', ctx, params);
await registry.setYaml('/msp.yaml', msp, msg || `Delete preset ${name} by ${author}`);
} catch (err) {
ctx.error = err;
await asyncInvoke('museCore.msp.failedDeletePreset', ctx, params);
throw err;
}
await asyncInvoke('museCore.msp.afterDeletePreset', ctx, params);
logger.info(`Delete preset success: ${name}.`);
return ctx;
};
92 changes: 92 additions & 0 deletions workspace/packages/muse-core/lib/msp/deletePreset.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
const { vol } = require('memfs');
const plugin = require('js-plugin');
const muse = require('../');
const { registry } = require('../storage');

const testJsPlugin = {
name: 'test-deletePreset',
museCore: {
msp: {
deletePreset: jest.fn(),
beforeDeletePreset: jest.fn(),
afterDeletePreset: jest.fn(),
},
},
};
plugin.register(testJsPlugin);

describe('deletePreset tests.', () => {
beforeEach(() => {
vol.reset();
});

it('should delete a preset from msp.yaml', async () => {
await registry.set(
'/msp.yaml',
`
default:
versions:
"@ebay/muse-core": "1.0.45"
muse-react:
extends: default
versions:
"@ebay/muse-lib-react": "2.0.3"
`,
);

await muse.msp.deletePreset({ name: 'muse-react', author: 'nate' });

const msp = await registry.getJsonByYaml('/msp.yaml');
expect(msp['muse-react']).toBeUndefined();
expect(msp.default).toBeDefined();

expect(testJsPlugin.museCore.msp.deletePreset).toBeCalledTimes(1);
expect(testJsPlugin.museCore.msp.beforeDeletePreset).toBeCalledTimes(1);
expect(testJsPlugin.museCore.msp.afterDeletePreset).toBeCalledTimes(1);
});

it('should throw if msp.yaml does not exist', async () => {
try {
await muse.msp.deletePreset({ name: 'default', author: 'nate' });
expect(true).toBe(false);
} catch (err) {
expect(err.message).toMatch('msp.yaml does not exist');
}
});

it('should throw if preset does not exist', async () => {
await registry.set('/msp.yaml', 'default:\n versions: {}\n');

try {
await muse.msp.deletePreset({ name: 'no-such-preset', author: 'nate' });
expect(true).toBe(false);
} catch (err) {
expect(err.message).toMatch('does not exist');
}
});

it('should throw and invoke failedDeletePreset on error', async () => {
const testJsPluginFails = {
name: 'test-deletePreset-fail',
museCore: {
msp: {
deletePreset: jest.fn().mockRejectedValue(new Error('storage error')),
beforeDeletePreset: jest.fn(),
afterDeletePreset: jest.fn(),
failedDeletePreset: jest.fn(),
},
},
};
plugin.register(testJsPluginFails);
await registry.set('/msp.yaml', 'default:\n versions: {}\n');

try {
await muse.msp.deletePreset({ name: 'default', author: 'nate' });
expect(true).toBe(false);
} catch (e) {
expect(e.message).toEqual('storage error');
}
expect(testJsPluginFails.museCore.msp.failedDeletePreset).toBeCalledTimes(1);
expect(testJsPluginFails.museCore.msp.afterDeletePreset).toBeCalledTimes(0);
});
});
32 changes: 32 additions & 0 deletions workspace/packages/muse-core/lib/msp/getMsp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
const { asyncInvoke, validate } = require('../utils');
const { registry } = require('../storage');
const schema = require('../schemas/msp/getMsp.json');
const logger = require('../logger').createLogger('muse.msp.getMsp');

/**
* @module muse-core/msp/getMsp
*/

/**
* @description Get all MSP presets as raw JSON from /msp.yaml.
* @param {object} [params={}]
* @returns {object|null} The parsed msp.yaml content, or null if it doesn't exist.
*/
module.exports = async (params = {}) => {
validate(schema, params);
const ctx = {};
logger.verbose('Getting msp...');
await asyncInvoke('museCore.msp.beforeGetMsp', ctx, params);

try {
ctx.msp = await registry.getJsonByYaml('/msp.yaml');
await asyncInvoke('museCore.msp.getMsp', ctx, params);
} catch (err) {
ctx.error = err;
await asyncInvoke('museCore.msp.failedGetMsp', ctx, params);
throw err;
}
await asyncInvoke('museCore.msp.afterGetMsp', ctx, params);
logger.verbose('Get msp success.');
return ctx.msp;
};
Loading