Skip to content

Commit

Permalink
Merge pull request #31 from AdobeXD/bootsie
Browse files Browse the repository at this point in the history
Bootsie
  • Loading branch information
ashryanbeats authored Dec 12, 2019
2 parents bbdeed8 + 29ede81 commit 5fd0396
Show file tree
Hide file tree
Showing 8 changed files with 294 additions and 74 deletions.
2 changes: 2 additions & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
*
**/*
47 changes: 33 additions & 14 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,28 +2,47 @@

`xdpm` is a command line tool that makes it easy to develop Adobe XD plugins. It is capable of the following tasks:

* `install`: copies one or more plugins in a develoment folder into Adobe XD's develop folder
* `watch`: Watches a plugin folder and copies it into Adobe XD whenever the contents change
* `validate`: Validates a plugin's manifest to ensure that it will be accepted by XD.
* `package`: Packages a plugin folder into an `xdx` file suitable for distribution
* `ls`: Lists plugins installed in Adobe XD in development mode.
- `bootstrap`: Creates a new plugin scaffold: headless, panel, react, modal. Optionally specify the name for your new plugin's directory.
- `install`: copies one or more plugins in a develoment folder into Adobe XD's develop folder
- `watch`: Watches a plugin folder and copies it into Adobe XD whenever the contents change
- `validate`: Validates a plugin's manifest to ensure that it will be accepted by XD.
- `package`: Packages a plugin folder into an `xdx` file suitable for distribution
- `ls`: Lists plugins installed in Adobe XD in development mode.

## Install

```
```shell
npm install -g @adobe/xdpm
```

If you've cloned the repository:

```
```shell
npm install
npm link
```

## Installing a plugin
## Bootstrapping a plugin

any of the following:

```shell
xdpm bootstrap # Bootstrap a headless plugin
xdpm bootstrap my-panel # Bootstrap a headless plugin in dir ./my-panel
xdpm bootstrap panel # Bootstrap a panel plugin
xdpm bootstrap panel my-panel # Bootstrap a panel plugin in dir ./my-panel
```

Plugin type options:

- headless (default)
- panel
- modal
- react

## Installing a plugin

```shell
xdpm install # Install the current folder into Adobe XD
xdpm install path/to/plugin # Install the specified folder into Adobe XD
xdpm install -w release # Install to Adobe XD CC Release (`r` is also valid; default)
Expand All @@ -38,7 +57,7 @@ If the plugin folder is not a valid XD plugin, you'll receive an error upon atte

## Watching a plugin

```
```shell
xdpm watch # Watch current folder and install changes into Adobe XD
xdpm watch path/to/plugin # Watch the specified folder and install changes into Adobe XD
xdpm watch -w release # Install to Adobe XD CC Release (`r` is also valid; default)
Expand All @@ -50,15 +69,15 @@ When developing a plugin, you can work directly in Adobe XD's `develop` folder,

## Validating plugin manifests

```
```shell
xdpm validate [...folders] # Validate the manifests in the list of folders
```

You can validate that a manifest is correct using this command. Any errors found will be listed; otherwise the report will be that the plugin validated successfully.

## Packaging plugins

```
```shell
xdpm package [...folders] # Create Adobe XD package
```

Expand All @@ -68,7 +87,7 @@ When you're finished with a plugin, you can simply zip the folder and rename the
## Listing installed plugins

```
```shell
xdpm ls # List installed plugins in Adobe XD's `develop` folder
xdpm ls -w release # List installed plugins in Adobe XD's `develop` folder (default)
xdpm ls -w prerelease # List installed plugins in Adobe XD Prerelease `develop` folder
Expand All @@ -78,7 +97,7 @@ You can install plugins that are currently installed in Adobe XD using `ls`.

## Help

```
```shell
Usage:
xdpm [OPTIONS] <command> [ARGS]

Expand Down Expand Up @@ -111,4 +130,4 @@ Apache 2.0
You use this utility at your own risk. Under no circumstances shall Adobe be held liable for the use, misuse, or abuse of this utility.
Use of this utility means that you agree to Adobe's [Terms of Use](https://www.adobe.com/legal/terms.html) and the [Adobe Developer Additional Terms](https://wwwimages2.adobe.com/content/dam/acom/en/legal/servicetou/Adobe-Developer-Additional-Terms_en_US_20180605_2200.pdf).
Use of this utility means that you agree to Adobe's [Terms of Use](https://www.adobe.com/legal/terms.html) and the [Adobe Developer Additional Terms](https://wwwimages2.adobe.com/content/dam/acom/en/legal/servicetou/Adobe-Developer-Additional-Terms_en_US_20180605_2200.pdf).
95 changes: 95 additions & 0 deletions commands/bootstrap.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
* Copyright 2018 Adobe Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
const shell = require("shelljs");
const sanitize = require("sanitize-filename");

const repo = "https://github.com/AdobeXD/plugin-samples.git";
const consoleLink = "https://console.adobe.io/plugins";
const defaultDirname = "my-plugin";
const sampleDirs = {
default: "quick-start",
headless: "quick-start",
panel: "quick-start-panel",
react: "quick-start-react",
modal: "ui-html"
};

function bootstrap(opts, args) {
shell.echo("Bootstrapping plugin:");

const sampleRepoDirname =
sampleDirs[args[0] || "default"] || sampleDirs.default;
const localDirname = getLocalDirname(args);

if (!shell.which("git")) {
shell.echo(
"Sorry, 'git' must be set in your PATH for xdpm bootstrap to work, but wasn't found. Please check your PATH."
);
shell.exit(1);
}

// Clone from repo
shell.exec(
`git clone "${repo}" "${localDirname}"`,
(code, stdout, stderr) => {
if (code === 0) {
cleanupClone(sampleRepoDirname, localDirname);
} else {
shell.echo(
`xdpm was unable to retrieve the boilerplate code for your plugin`
);
shell.echo(`See the following for more information:`);
shell.echo(`> ${stdout}`);
shell.echo(`> ${stderr}`);

shell.exit(1);
}
}
);
}

function getLocalDirname(args) {
if (args[1]) return sanitize(args[1]);
if (args[0] && !sampleDirs[args[0]]) return sanitize(args[0]);
return defaultDirname;
}

// Remove unneeded samples and git history
function cleanupClone(sampleRepoDirname, localDirname) {
const cdResult = shell.cd(`./${localDirname}`);

if (cdResult.code === 0) {
shell.exec(
`git filter-branch --subdirectory-filter "${sampleRepoDirname}"`,
{ silent: true }
);
shell.rm("-rf", `.git`);

shell.echo(`Plugin was sucessfully bootstrapped in ${localDirname}`);
shell.echo(
`Be sure to get your unique plugin ID at ${consoleLink} and include it in manifest.json`
);
} else {
shell.echo(`Unable to find bootstrapped plugin directory ${localDirname}`);

shell.exit(1);
}
}

module.exports = {
bootstrap,
sampleDirs
};
36 changes: 32 additions & 4 deletions commands/validate.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
*/

const cli = require("cli");
const shell = require("shelljs");
const path = require("path");
const getPluginMetadata = require("../lib/getPluginMetadata");
const validate = require("../lib/validate");

const validateErrCode = 1;

/**
* validates one or more plugins
*/
Expand All @@ -27,6 +30,19 @@ function validatePlugin(opts, args) {
args.push("."); // assume we want to package the plugin in the cwd
}

const results = getResults(args);
const errors = reportResults(opts, results);

if (errors) {
cli.error(`Manifest validation failed. Exiting with code ${validateErrCode}`);
shell.exit(validateErrCode);
}
else {
shell.exit(0);
}
}

function getResults(args) {
const results = args.map(pluginToValidate => {
const sourcePath = path.resolve(pluginToValidate);
const result = {
Expand All @@ -51,20 +67,32 @@ function validatePlugin(opts, args) {
return result;
});

return results;
}

/**
* Prints validation results for each tested plugin to command line.
* @param {*} opts
* @param {*} results
* @returns {boolean} True if there was an error for any of the tested plugin manifests.
*/
function reportResults(opts, results) {
if (opts.json) {
cli.output(JSON.stringify(results));
return results;
}
shell.echo(JSON.stringify(results));
}

let errors;

results.forEach(result => {
if (result.ok) {
cli.ok(result.ok);
} else {
cli.error(result.error);
errors = true;
}
});

return results;
return errors;
}

module.exports = validatePlugin;
79 changes: 49 additions & 30 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,58 +17,77 @@

const cli = require("cli");
const package = require("./package.json");
const sampleDirs = require("./commands/bootstrap").sampleDirs;
const sampleTypes = Object.keys(sampleDirs)
.filter(el => el !== "default")
.join(", ");


cli.enable("status", "version");
cli.setApp(package.name, package.version);

const commands = {
"install": "Install a plugin in development mode",
"ls": "List all plugins in development mode",
"package": "Package a plugin",
"validate": "Validate a plugin's manifest",
"watch": "Watch a plugin directory. If no directory is specified, `.` is assumed",
bootstrap: `Create a new plugin scaffold: ${sampleTypes}. Optionally specify the name for your new plugin's directory.`,
install: "Install a plugin in development mode",
ls: "List all plugins in development mode",
package: "Package a plugin",
validate: "Validate a plugin's manifest",
watch:
"Watch a plugin directory. If no directory is specified, `.` is assumed"
};

const options = {
clean: ["c", "Clean before install", "bool", false],
json: ["j", "If true, indicates that JSON output should be generated", "bool", false],
// mode: ["m", "Indicates which plugin mode to use", ["d", "p"], "d"],
overwrite: ["o", "Allow overwriting plugins", "bool", false],
which: ["w", "Which Adobe XD instance to target", ["r", "p", "d", "release", "pre", "prerelease", "dev", "development"], "r"],
clean: ["c", "Clean before install", "bool", false],
json: [
"j",
"If true, indicates that JSON output should be generated",
"bool",
false
],
// mode: ["m", "Indicates which plugin mode to use", ["d", "p"], "d"],
overwrite: ["o", "Allow overwriting plugins", "bool", false],
which: [
"w",
"Which Adobe XD instance to target",
["r", "p", "d", "release", "pre", "prerelease", "dev", "development"],
"r"
]
};

const parsedOpts = cli.parse(options, commands);

if (parsedOpts.json) {
cli.status = function() {};
cli.status = function() {};
} else {
cli.info(`xdpm ${package.version} - XD Plugin Manager CLI`);
cli.info(`Use of this tool means you agree to the Adobe Terms of Use at
cli.info(`xdpm ${package.version} - XD Plugin Manager CLI`);
cli.info(`Use of this tool means you agree to the Adobe Terms of Use at
https://www.adobe.com/legal/terms.html and the Developer Additional
Terms at https://wwwimages2.adobe.com/content/dam/acom/en/legal/servicetou/Adobe-Developer-Additional-Terms_en_US_20180605_2200.pdf.`)
Terms at https://wwwimages2.adobe.com/content/dam/acom/en/legal/servicetou/Adobe-Developer-Additional-Terms_en_US_20180605_2200.pdf.`);
}

const { command, args } = cli;

if (parsedOpts.which) {
parsedOpts.which = parsedOpts.which[0];
parsedOpts.which = parsedOpts.which[0];
}

switch (command.toLowerCase()) {
case "ls":
require("./commands/ls")(parsedOpts, args);
break;
case "install":
require("./commands/install")(parsedOpts, args);
break;
case "watch":
require("./commands/watch")(parsedOpts, args);
break;
case "package":
require("./commands/package")(parsedOpts, args);
break;
case "validate":
require("./commands/validate")(parsedOpts, args);
break;
case "ls":
require("./commands/ls")(parsedOpts, args);
break;
case "install":
require("./commands/install")(parsedOpts, args);
break;
case "watch":
require("./commands/watch")(parsedOpts, args);
break;
case "package":
require("./commands/package")(parsedOpts, args);
break;
case "validate":
require("./commands/validate")(parsedOpts, args);
break;
case "bootstrap":
require("./commands/bootstrap").bootstrap(parsedOpts, args);
break;
}
Loading

0 comments on commit 5fd0396

Please sign in to comment.