Skip to content
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

Allowing custom folder name for plugin installation #446

Closed
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
Binary file not shown.
5 changes: 2 additions & 3 deletions src/cli_plugin/install/install.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ import { download } from './download';
import { cleanPrevious, cleanArtifacts } from './cleanup';
import { extract, getPackData } from './pack';
import { renamePlugin } from './rename';
import { existingInstall, assertVersion } from './opensearch_dashboards';
import { kebabCase } from 'lodash';
import { existingInstall, assertVersion, getTargetFolderName } from './opensearch_dashboards';

const mkdir = promisify(Fs.mkdir);

Expand All @@ -63,7 +62,7 @@ export async function install(settings, logger) {

assertVersion(settings);

const targetDir = path.join(settings.pluginDir, kebabCase(settings.plugins[0].id));
const targetDir = path.join(settings.pluginDir, getTargetFolderName(settings));
await renamePlugin(settings.workingPath, targetDir);

logger.log('Plugin installation complete');
Expand Down
25 changes: 17 additions & 8 deletions src/cli_plugin/install/opensearch_dashboards.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,15 +37,18 @@ import { kebabCase } from 'lodash';
import { versionSatisfies, cleanVersion } from '../../legacy/utils/version';

export function existingInstall(settings, logger) {
try {
statSync(path.join(settings.pluginDir, kebabCase(settings.plugins[0].id)));
Copy link
Member

Choose a reason for hiding this comment

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

You may have been right to worry that previous versions of plugins may have been installed into settings.plugins[0].id (1.1 installation on top of 1.0). Is that a valid concern. If so, make an array of all possible folder names, and do a foreach on them to check.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

One of the cases I can think of now is the user first used the id of the plugin to install it, then added a folderName property to opensearch_dashboards.json and tried installing again. It should fail saying the plugin is already installed. I will add both the checks to be on the safer side.

const folderNames = [kebabCase(settings.plugins[0].id), getTargetFolderName(settings)];
for (const folderName of folderNames) {
try {
statSync(path.join(settings.pluginDir, folderName));

logger.error(
`Plugin ${settings.plugins[0].id} already exists, please remove before installing a new version`
);
process.exit(70);
} catch (e) {
if (e.code !== 'ENOENT') throw e;
logger.error(
`Plugin ${settings.plugins[0].id} already exists with folder name ${folderName}, please remove before installing a new version`
);
process.exit(70);
} catch (e) {
if (e.code !== 'ENOENT') throw e;
}
}
}

Expand All @@ -64,3 +67,9 @@ export function assertVersion(settings) {
);
}
}

export function getTargetFolderName(settings) {
return typeof settings.plugins[0].folderName === 'string' && settings.plugins[0].folderName
? settings.plugins[0].folderName
: kebabCase(settings.plugins[0].id);
}
41 changes: 40 additions & 1 deletion src/cli_plugin/install/opensearch_dashboards.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ import fs from 'fs';
import sinon from 'sinon';
import del from 'del';

import { existingInstall, assertVersion } from './opensearch_dashboards';
import { existingInstall, assertVersion, getTargetFolderName } from './opensearch_dashboards';
import { Logger } from '../lib/logger';

jest.spyOn(fs, 'statSync');
Expand Down Expand Up @@ -159,6 +159,45 @@ describe('opensearchDashboards cli', function () {
expect(logger.error.called).toBe(false);
});
});

describe('getTargetFolderName', function () {
beforeEach(function () {
del.sync(testWorkingPath);
fs.mkdirSync(testWorkingPath, { recursive: true });
sinon.stub(logger, 'log');
sinon.stub(logger, 'error');
});

afterEach(function () {
logger.log.restore();
logger.error.restore();
del.sync(testWorkingPath);
});

it('should return the id for target folder name', function () {
const targetFolderName = settings.plugins[0].id;

expect(getTargetFolderName(settings)).toEqual(targetFolderName);
});

it('should return the custom folder name for target folder name', function () {
const settingsWithCustomFolderName = {
workingPath: testWorkingPath,
tempArchiveFile: tempArchiveFilePath,
plugin: 'test-plugin',
version: '1.0.0',
plugins: [
{
id: 'foo',
folderName: 'custom-folder',
},
],
pluginDir,
};

expect(getTargetFolderName(settingsWithCustomFolderName)).toEqual('custom-folder');
});
});
});
});

Expand Down
20 changes: 20 additions & 0 deletions src/cli_plugin/install/pack.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,7 @@ describe('opensearchDashboards cli', function () {
expect(settings.plugins).toMatchInlineSnapshot(`
Array [
Object {
"folderName": undefined,
"id": "testPlugin",
"opensearchDashboardsVersion": "1.0.0",
"stripPrefix": "opensearch-dashboards/test-plugin",
Expand All @@ -134,6 +135,7 @@ describe('opensearchDashboards cli', function () {
expect(settings.plugins).toMatchInlineSnapshot(`
Array [
Object {
"folderName": undefined,
"id": "testPlugin",
"opensearchDashboardsVersion": "5.0.1",
"stripPrefix": "opensearch-dashboards/test-plugin",
Expand All @@ -148,16 +150,19 @@ describe('opensearchDashboards cli', function () {
expect(settings.plugins).toMatchInlineSnapshot(`
Array [
Object {
"folderName": undefined,
"id": "fungerPlugin",
"opensearchDashboardsVersion": "1.0.0",
"stripPrefix": "opensearch-dashboards/funger-plugin",
},
Object {
"folderName": undefined,
"id": "pdf",
"opensearchDashboardsVersion": "1.0.0",
"stripPrefix": "opensearch-dashboards/pdf",
},
Object {
"folderName": undefined,
"id": "testPlugin",
"opensearchDashboardsVersion": "1.0.0",
"stripPrefix": "opensearch-dashboards/test-plugin",
Expand All @@ -166,6 +171,21 @@ describe('opensearchDashboards cli', function () {
`);
});

it('populate settings.plugin.folderName', async () => {
await copyReplyFile('test_plugin_custom_folder.zip');
await getPackData(settings, logger);
expect(settings.plugins).toMatchInlineSnapshot(`
Array [
Object {
"folderName": "custom-plugin-name",
"id": "testPlugin",
"opensearchDashboardsVersion": "1.0.0",
"stripPrefix": "opensearch-dashboards/test-plugin-custom-folder",
},
]
`);
});

it('throw an error if there is no opensearch-dashboards plugin', async () => {
await copyReplyFile('test_plugin_no_opensearch_dashboards.zip');
await expect(getPackData(settings, logger)).rejects.toThrowErrorMatchingInlineSnapshot(
Expand Down
1 change: 1 addition & 0 deletions src/cli_plugin/install/zip.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ export function analyzeArchive(archive) {
plugins.push({
id: manifest.id,
stripPrefix: match[1],
folderName: manifest.folderName,

// Plugins must specify their version, and by default that version in the plugin
// manifest should match the version of opensearch-dashboards down to the patch level. If these
Expand Down
1 change: 1 addition & 0 deletions src/cli_plugin/install/zip.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ describe('opensearchDashboards cli', function () {
expect(packages).toMatchInlineSnapshot(`
Array [
Object {
"folderName": undefined,
"id": "testPlugin",
"opensearchDashboardsVersion": "1.0.0",
"stripPrefix": "opensearch-dashboards/test-plugin",
Expand Down
10 changes: 2 additions & 8 deletions src/cli_plugin/list/list.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,15 @@
* GitHub history for details.
*/

import { statSync, readdirSync, readFileSync } from 'fs';
import { statSync, readdirSync } from 'fs';
import { join } from 'path';

export function list(pluginDir, logger) {
readdirSync(pluginDir).forEach((name) => {
const stat = statSync(join(pluginDir, name));

if (stat.isDirectory() && name[0] !== '.') {
try {
const packagePath = join(pluginDir, name, 'opensearch_dashboards.json');
const pkg = JSON.parse(readFileSync(packagePath, 'utf8'));
logger.log(pkg.id + '@' + pkg.version);
} catch (e) {
throw new Error('Unable to read opensearch_dashboards.json file for plugin ' + name);
}
Copy link
Member

Choose a reason for hiding this comment

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

What's the reason to remove this?

Copy link
Contributor Author

@VachaShah VachaShah Jun 16, 2021

Choose a reason for hiding this comment

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

For the list command, the output printed was <pluginId>@<pluginVersion> but this same output could not be used in the remove command, this was mentioned in the same issue #322 in the latest comments, I removed this so that the actual folder name can be printed which the user can use to remove the plugin with the remove command. LMK if you think this could be better.

logger.log(name);
}
});

Expand Down
30 changes: 3 additions & 27 deletions src/cli_plugin/list/list.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -85,36 +85,12 @@ describe('opensearchDashboards cli', function () {

expect(logger.messages).toMatchInlineSnapshot(`
Array [
"log: plugin1@5.0.0-alpha2",
"log: plugin2@3.2.1",
"log: plugin3@1.2.3",
"log: plugin1",
"log: plugin2",
"log: plugin3",
"log: ",
]
`);
});

it('list should throw an exception if a plugin does not have a package.json', function () {
createPlugin('plugin1', '1.0.0', pluginDir);
mkdirSync(join(pluginDir, 'empty-plugin'), { recursive: true });

expect(function () {
list(pluginDir, logger);
}).toThrowErrorMatchingInlineSnapshot(
`"Unable to read opensearch_dashboards.json file for plugin empty-plugin"`
);
});

it('list should throw an exception if a plugin have an empty package.json', function () {
createPlugin('plugin1', '1.0.0', pluginDir);
const invalidPluginDir = join(pluginDir, 'invalid-plugin');
mkdirSync(invalidPluginDir, { recursive: true });
writeFileSync(join(invalidPluginDir, 'package.json'), '');

expect(function () {
list(pluginDir, logger);
}).toThrowErrorMatchingInlineSnapshot(
`"Unable to read opensearch_dashboards.json file for plugin invalid-plugin"`
);
});
});
});