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

Plugins that only live in your project. #886

Merged
merged 2 commits into from
Mar 11, 2017
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
32 changes: 13 additions & 19 deletions docs/README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,19 @@
# Ignite Documentation

This is a list of documentation ideas.

## Advanced Guides
## Quick Start

* Creating plugins from scratch
* Creating plugins from an existing component
* Sporking template (why and how)
* How to test your plugin
* Creating your own "extensions" (these are 'libraries' things that can be used by plugins - such as file patching)
* Installing
* [Getting started](./quick-start/getting-started.md)
* [Ignite commands](./quick-start/ignite-commands.md)
* [Using boilerplates](./quick-start/using-boilerplates.md)
* Removing plugins
* Spork! - tweaking 3rd-party generators

## API
## Advanced Guides

## Quick Start
* [Creating plugins](./advanced-guides/creating-plugins.md)
* [Creating project plugins](./advanced-guides/creating-project-plugins.md)
* Writing tests for plugins
* Releasing plugins
* Creating extensions

* Using boilerplates
* Removing plugins you don't like
* Project plugins vs 3rd party plugins
* Gluegun and its features
* App structure
* Use and adding Generators
* Adding plugins
* Editing generators and the templates they use
* Ignite commands
8 changes: 2 additions & 6 deletions docs/advanced-guides/creating-plugins.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,25 +21,21 @@ Open up `package.json` and add your desired info.
{
"name": "ignite-radio-buttons",
"version": "0.0.1",
"description": "",
"description": "An Ignite plugin for react-native-radio-buttons.",
"license": "MIT",
"devDependencies": {},
"url": "https://github.com/infinitered/ignite-radio-buttons/issues",
"author": {
"name": "Robin Heinze",
"email": "robin@infinite.red",
"url": "https://infinite.red"
},
"devEngines": {
"node": ">=7.x",
"npm": ">=4.x"
}
}
```

### Edit the `index.js`

The `index.js` is the entrypoint for your plugin and provides the add/remove functionality. We need to make sure that the npm packages installed and component examples are copied over.
The `index.js` is the entrypoint for your plugin and provides the add/remove functionality. We need to make sure that the npm packages installed and component examples are copied over.

1. Change the `NPM_MODULE_NAME` to `react-native-radio-buttons`
2. Since this npm package does not require a linking step, we will change `ignite.addModule` to have `link: false` and `ignite.removeModule` to have `unlink: false`
Expand Down
72 changes: 72 additions & 0 deletions docs/advanced-guides/creating-project-plugins.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
# Creating Project Plugins

First read the [creating plugins guide](./creating-plugins.md). It covers the structure of plugins.

Project-based plugins are plugins which stay within your repo. They're a great way to add some features to Ignite without going through the hassle or commitment of publishing to NPM.

Some examples of this might be:

* generators that make little sense outside your project
* scripts that are a bit more complex than a one liner inside your `package.json`
* a playground for exploring ignite
* a proving arena for plugins you intend to build & release, but aren't quite ready yet

## The ignite/plugins Directory

You place your plugins in the `ignite/plugins` directory. Plugins are directories themselves, so begin by creating a `sample` directory there.

In this directory, create a file called `ignite.json` and put this empty object inside:

```json
{}
```

Next create a new text file in that directory, naming it `ignite.toml`. Inside, place this:

```toml
description = "🔥🔥🔥 It's plugin time!🔥🔥🔥"
```

> Note! This will be replaced shortly with `ignite.json`. I just need to patch up gluegun to provide a post-load hook so ignite can do this.

## Running Your Plugin

Back in the project root, type:

```sh
ignite
```

You should see your plugin appear. Now, let's list the commands that you've made:

```sh
ignite sample
```

Empty. Let's make one by creating a new directory: `ignite/plugins/sample/commands`. In that directory place this `online.js`.

```js
// @cliDescription Let's gather some useful data on this mission!

module.exports = context => {
const { filesystem, print } = context
const { colors } = print

const pkg = filesystem.read('package.json', 'json')
const depsCount = Object.keys(pkg.dependencies || {}).length
print.info(`You have ${colors.bold(depsCount)} direct dependencies. And they are awesome.`)
}

```

```sh
ignite sample
```

Now you have one. Let's run it.

```sh
ignite sample online
```

For more details on creating commands (including generators), check out [the guide to plugins](./creating-plugins.md) and the [context API guide](https://infinitered.github.io/gluegun/#/context-api).
1 change: 1 addition & 0 deletions packages/ignite-cli/src/cli/cli.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const buildIgnite = () => {
return build()
.brand('ignite')
.loadDefault(`${__dirname}/..`)
.loadAll(`${process.cwd()}/ignite/plugins`)
.loadAll(`${process.cwd()}/node_modules`, { matching: 'ignite-*', hidden: true })
.token('commandName', 'cliCommand')
.token('commandHidden', 'cliHidden')
Expand Down
37 changes: 25 additions & 12 deletions packages/ignite-cli/src/extensions/ignite/findIgnitePlugins.js
Original file line number Diff line number Diff line change
@@ -1,20 +1,33 @@
const { pipe, filter, propSatisfies, sortBy, prop } = require('ramda')
const {
contains,
anyPass,
pipe,
filter,
propSatisfies,
sortBy,
prop
} = require('ramda')
const { startsWith } = require('ramdasauce')

module.exports = (plugin, command, context) => {
// gluegun stuff
const { runtime, filesystem: { separator } } = context

// how to identify ignite plugins
const ignitePrefixed = propSatisfies(startsWith('ignite-'), 'name')
const isInRightLocation = contains(`ignite${separator}plugins`)
const inProjectPlugins = propSatisfies(isInRightLocation, 'directory')
const onlyIgnitePlugins = filter(anyPass([ignitePrefixed, inProjectPlugins]))
const getIgnitePlugins = pipe(onlyIgnitePlugins, sortBy(prop('name')))

/**
* Finds the gluegun plugins that are also ignite plugins.
* Finds the gluegun plugins that are also ignite plugins. These are
* plugins which have 1 of the following:
*
* - the name starts with "ignite-"
* - the directory contains "ignite/plugins"
*
* @returns {Plugin[]} - an array of ignite plugins
*/
function findIgnitePlugins () {
const { runtime } = context

return pipe(
filter(propSatisfies(startsWith('ignite-'), 'name')),
sortBy(prop('name'))
)(runtime.plugins)
}

return findIgnitePlugins
return () => getIgnitePlugins(runtime.plugins)
}
4 changes: 4 additions & 0 deletions packages/ignite-cli/tests/cli/cliConfig.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ test('ignite', async t => {
t.deepEqual(builderProps, {
brand: 'ignite',
loadAlls: [
{
dir: `${process.cwd()}/ignite/plugins`,
opts: {}
},
{
dir: `${process.cwd()}/node_modules`,
opts: { hidden: true, matching: 'ignite-*' }
Expand Down
54 changes: 54 additions & 0 deletions packages/ignite-cli/tests/extensions/findIgnitePlugins.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
const test = require('ava')
const extension = require('../../src/extensions/ignite/findIgnitePlugins')

test('has the right interface', t => {
t.is(typeof extension, 'function')
const context = { filesystem: { separator: '/' } }
const findIgnitePlugin = extension(null, null, context)
t.is(typeof findIgnitePlugin, 'function')
})

test('plugin-less', t => {
const context = {
filesystem: { separator: '/' },
runtime: {
plugins: []
}
}
const findIgnitePlugin = extension(null, null, context)
t.deepEqual(findIgnitePlugin(), [])
})

test('skips non-ignite plugins', t => {
const context = {
filesystem: { separator: '/' },
runtime: {
plugins: [{ name: 'x', directory: 'y' }]
}
}
const findIgnitePlugin = extension(null, null, context)
t.deepEqual(findIgnitePlugin(), [])
})

test('finds ignite- prefixed plugins', t => {
const context = {
filesystem: { separator: '/' },
runtime: {
plugins: [{ name: 'ignite-foo', directory: 'y' }]
}
}
const findIgnitePlugin = extension(null, null, context)
t.deepEqual(findIgnitePlugin(), [{ name: 'ignite-foo', directory: 'y' }])
})

test('finds project plugins', t => {
const dir = `${process.cwd()}/ignite/plugins/y`
const context = {
filesystem: { separator: '/' },
runtime: {
plugins: [{ name: 'x', directory: dir }]
}
}
const findIgnitePlugin = extension(null, null, context)
t.deepEqual(findIgnitePlugin(), [{ name: 'x', directory: dir }])
})
3 changes: 3 additions & 0 deletions packages/ignite-cli/tests/extensions/ignite.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ test('has the right interface', t => {
},
system: {
which: () => true
},
filesystem: {
separator: '/'
}
}
const extension = attach(plugin, command, context)
Expand Down