Skip to content

feat: allow plugins to use the userConfig object to set arbitrary data #118

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 13, 2021
17 changes: 17 additions & 0 deletions src/services/config.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ class ConfigData {
this.prompts = {};
this.profiles = [];
this.activeProfile = null;
this.plugins = {};
}

getProfileFromEnvironment() {
Expand Down Expand Up @@ -142,6 +143,18 @@ class ConfigData {
prompt.acked = true;
}

setPluginData(pluginName, data) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, I like this idea and the clean naming convention.

With this setup, it seems like we need to be careful with name spacing to avoid unintended data manipulation. Perhaps the pluginName needs to be <org>/<name of plugin>.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's not much we can do about data manipulation, any plugin can overwrite the entire userConfig if it wanted to. The idea that setting the plugin name (which could be defined as "serverless" or "@twilio-labs/plugin-serverless", for example) should be a unique namespace.

A better alternative would be to have the function setPluginData(data) and the name get read from the plugin itself. But I don't know if plugin name/namespace is available to the plugin during runtime. Do you know if that is possible?

this.plugins[pluginName] = data;
}

getPluginData(pluginName) {
return this.plugins[pluginName];
}

removePluginData(pluginName) {
delete this.plugins[pluginName];
}

loadFromObject(configObj) {
this.edge = configObj.edge;
this.email = configObj.email || {};
Expand All @@ -150,6 +163,9 @@ class ConfigData {
configObj.profiles = configObj.projects || [];
configObj.profiles.forEach((profile) => this.addProfile(profile.id, profile.accountSid, profile.region));
this.setActiveProfile(configObj.activeProject);
Object.keys(configObj.plugins).forEach((pluginName) =>
this.setPluginData(pluginName, configObj.plugins[pluginName]),
);
}

sanitize(string) {
Expand Down Expand Up @@ -183,6 +199,7 @@ class Config {
// Note the historical 'projects' naming.
projects: configData.profiles,
activeProject: configData.activeProfile,
plugins: configData.plugins,
};

fs.mkdirSync(this.configDir, { recursive: true });
Expand Down
32 changes: 32 additions & 0 deletions test/services/config.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,37 @@ describe('services', () => {
});
});

describe('ConfigData.setPluginData', () => {
test.it('should add data for a new plugin', () => {
const configData = new ConfigData();
expect(configData.getPluginData('fancy-plugin')).to.be.undefined;
const testData = { arbitrary: 'data' };
configData.setPluginData('fancy-plugin', testData);

expect(configData.getPluginData('fancy-plugin')).to.deep.equal(testData);
});

test.it('should update data for an existing plugin', () => {
const configData = new ConfigData();
const testData = { arbitrary: 'data' };
const newData = { new: 'information' };
configData.setPluginData('fancy-plugin', testData);
configData.setPluginData('fancy-plugin', newData);

expect(configData.getPluginData('fancy-plugin')).to.deep.equal(newData);
expect(configData.getPluginData('fancy-plugin').arbitrary).to.be.undefined;
});

test.it('should remove data for plugin', () => {
const configData = new ConfigData();
const testData = { arbitrary: 'data' };
configData.setPluginData('fancy-plugin', testData);
configData.removePluginData('fancy-plugin');

expect(configData.getPluginData('fancy-plugin')).to.be.undefined;
});
});

describe('Config', () => {
const tempConfigDir = tmp.dirSync({ unsafeCleanup: true });

Expand All @@ -212,6 +243,7 @@ describe('services', () => {
userConfig.addProfile(' profile \t', 'sid \n ', ' stage');
userConfig.setActiveProfile('\tprofile\t');
userConfig.ackPrompt('impromptu');
userConfig.setPluginData('fancy-plugin', 'plugin-data');

const saveMessage = await config.save(userConfig);
expect(saveMessage).to.contain(`${tempConfigDir.name}${path.sep}config.json`);
Expand Down