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

feat: add template option to plugin create command #3836

Merged
merged 3 commits into from
Aug 23, 2018
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
15 changes: 13 additions & 2 deletions docs/man_pages/lib-management/plugin-create.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,8 @@ position: 1

Usage | Synopsis
---|---
Create a new plugin | `$ tns plugin create <Plugin Repository Name> [--path <Directory>]`
Create from the default plugin seed | `$ tns plugin create <Plugin Repository Name> [--path <Directory>]`
Create from a custom plugin seed | `$ tns plugin create <Plugin Repository Name> [--path <Directory>] --template <Template>`

Creates a new project for NativeScript plugin development. The project uses the [NativeScript Plugin Seed](https://github.com/NativeScript/nativescript-plugin-seed) as a base and contains the following directories:

Expand All @@ -20,9 +21,19 @@ The project is setup for easy commit in Github, which is why the command will as
### Options

* `--path` - Specifies the directory where you want to create the project, if different from the current directory.
* `--template` - Specifies the custom seed archive, which you want to use to create your plugin. If `--template` is not set, the NativeScript CLI creates the plugin from the default NativeScript Plugin Seed.
* `--username` - Specifies the Github username, which will be used to build the URLs in the plugin's package.json file.
* `--pluginName` - Used to set the default file and class names in the plugin source.

### Attributes

* `<Plugin Repository Name>` is the name of repository where your plugin will reside. A directory with the same name will be created. For example: `nativescript-awesome-list`. If a directory with the name already exists and is not empty, the plugin create command will fail.
* `<Plugin Repository Name>` is the name of repository where your plugin will reside. A directory with the same name will be created. For example: `nativescript-awesome-list`. If a directory with the name already exists and is not empty, the plugin create command will fail.<% if(isHtml) { %>
* `<Template>` can be a URL or a local path to a `.tar.gz` file with the contents of a seed repository. This must be a clone of the [NativeScript Plugin Seed](https://github.com/NativeScript/nativescript-plugin-seed) and must contain a `src` directory with a package.json file and a script at `src/scripts/postclone.js`. After the archive is extracted, the postclone script will be executed with the username (`gitHubUsername`) and plugin name (`pluginName`) parameters given to the `tns plugin create` command prompts. For more information, visit the default plugin seed repository and [examine the source script](https://github.com/NativeScript/nativescript-plugin-seed/blob/master/src/scripts/postclone.js) there. Examples:
Copy link
Contributor

Choose a reason for hiding this comment

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

can be a URL or a local path to a .tar.gz -> in fact it can be anything that can be npm installed, you can pass a local dir path with correct structure (i.e. local copy of the plugin seed for example) and it should work,

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried it and it only worked with .tar.gz archive. I suppose this is because the plugin seed does not have a package.json file in the root of the repository and it cannot be packed directly as an npm package.


* Using a local file:

`tns plugin create nativescript-testplugin --template ../seeds/seed1.tar.gz`

* Using a `.tar.gz` file from a tag called `v4.0` in a Github repository:

`tns plugin create nativescript-testplugin --template https://github.com/NativeScript/nativescript-plugin-seed/archive/v.4.0.tar.gz`<% } %>
18 changes: 12 additions & 6 deletions lib/commands/plugin/create-plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,11 @@ export class CreatePluginCommand implements ICommand {
public async execute(args: string[]): Promise<void> {
const pluginRepoName = args[0];
const pathToProject = this.$options.path;
const selectedTemplate = this.$options.template;
const selectedPath = path.resolve(pathToProject || ".");
const projectDir = path.join(selectedPath, pluginRepoName);

this.$logger.printMarkdown("Downloading the latest version of NativeScript Plugin Seed...");
await this.downloadPackage(projectDir);

this.$logger.printMarkdown("Executing initial plugin configuration script...");
await this.downloadPackage(selectedTemplate, projectDir);
await this.setupSeed(projectDir, pluginRepoName);

this.$logger.printMarkdown("Solution for `%s` was successfully created.", pluginRepoName);
Expand All @@ -39,6 +37,8 @@ export class CreatePluginCommand implements ICommand {
}

private async setupSeed(projectDir: string, pluginRepoName: string): Promise<void> {
this.$logger.printMarkdown("Executing initial plugin configuration script...");

const config = this.$options;
const spinner = this.$terminalSpinnerService.createSpinner();
const cwd = path.join(projectDir, "src");
Expand Down Expand Up @@ -66,15 +66,21 @@ export class CreatePluginCommand implements ICommand {
}
}

private async downloadPackage(projectDir: string): Promise<void> {
private async downloadPackage(selectedTemplate: string, projectDir: string): Promise<void> {
this.$fs.createDirectory(projectDir);

if (this.$fs.exists(projectDir) && !this.$fs.isEmptyDir(projectDir)) {
this.$errors.fail("Path already exists and is not empty %s", projectDir);
}

if (selectedTemplate) {
this.$logger.printMarkdown("Make sure your custom template is compatible with the Plugin Seed at https://github.com/NativeScript/nativescript-plugin-seed/");
} else {
this.$logger.printMarkdown("Downloading the latest version of NativeScript Plugin Seed...");
}

const spinner = this.$terminalSpinnerService.createSpinner();
const packageToInstall = "https://github.com/NativeScript/nativescript-plugin-seed/archive/master.tar.gz";
const packageToInstall = selectedTemplate || "https://github.com/NativeScript/nativescript-plugin-seed/archive/master.tar.gz";
try {
spinner.start();
await this.$pacoteService.extractPackage(packageToInstall, projectDir);
Expand Down
34 changes: 32 additions & 2 deletions test/plugin-create.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,16 @@ import { CreatePluginCommand } from "../lib/commands/plugin/create-plugin";
import { assert } from "chai";
import helpers = require("../lib/common/helpers");

interface IPacoteOutput {
packageName: string;
destinationDirectory: string;
}

const originalIsInteractive = helpers.isInteractive;
const dummyArgs = ["dummyProjectName"];
const dummyUser = "devUsername";
const dummyName = "devPlugin";
const dummyPacote: IPacoteOutput = { packageName: "", destinationDirectory: "" };

function createTestInjector() {
const testInjector = new Yok();
Expand All @@ -21,7 +27,9 @@ function createTestInjector() {
testInjector.register("npm", stubs.NpmInstallationManagerStub);
testInjector.register("options", {
username: undefined,
pluginName: undefined
pluginName: undefined,
template: undefined,
path: undefined
});

testInjector.register("terminalSpinnerService", {
Expand All @@ -34,7 +42,11 @@ function createTestInjector() {

testInjector.register("pacoteService", {
manifest: () => Promise.resolve(),
extractPackage: () => Promise.resolve()
extractPackage: (packageName: string, destinationDirectory: string) => {
dummyPacote.destinationDirectory = destinationDirectory;
dummyPacote.packageName = packageName;
return Promise.resolve();
}
});

testInjector.register("createCommand", CreatePluginCommand);
Expand Down Expand Up @@ -63,6 +75,24 @@ describe("Plugin create command tests", () => {
assert.isRejected(createPluginCommand.canExecute([]));
});

it("should use correct directory when path parameter is passed", async () => {
helpers.isInteractive = () => false;
const dummyPath = "dummyPath";
options.path = dummyPath;
dummyPacote.destinationDirectory = "";
await createPluginCommand.execute(dummyArgs);
assert.include(dummyPacote.destinationDirectory, dummyPath);
});

it("should use correct download path when template parameter is passed", async () => {
helpers.isInteractive = () => false;
const dummyTemplate = "dummyTemplate";
options.template = dummyTemplate;
dummyPacote.packageName = "";
await createPluginCommand.execute(dummyArgs);
assert.equal(dummyPacote.packageName, dummyTemplate);
});

it("should pass when only project name is set in non-interactive shell.", async () => {
helpers.isInteractive = () => false;
await createPluginCommand.execute(dummyArgs);
Expand Down