README.md

![PhilColumns: No Fixtures Required](https://raw.githubusercontent.com/midas/phil_columns/master/readme/PhilColumns.png)

# PhilColumns

A full featured Elixir/Ecto seeding solution providing means for dev and prod seeding.


## Installation

Add phil_columns to your list of dependencies in `mix.exs`:

```elixir
def deps do
  [{:phil_columns, "~> 0.1.0"}]
end
```

Ensure phil_columns is started before your application:

```elixir
def application do
  [applications: [:phil_columns]]
end
```

Create a `Seed` module for you application:

```elixir
# lib/my_app/seed.ex

defmodule MyApp.Seed do
  defmacro __using__(_opts) do
    quote do
      use PhilColumns.Seed

      # shared code here ...
    end
  end
end
```

## Configuration

If you need to ensure applications are started before seeding, configure them like this:

```elixir
config :phil_columns,
  ensure_all_started: ~w(timex)a
```


## Usage

### Seeding Quick Start

Use the generator to create a seed.

    $ mix phil_columns.gen.seed add_things

The generator puts a seed file in place.  Add your seeding logic to the `up/1` and/or `down/1`
functions using any valid Elixir/Ecto code.

```elixir
# priv/repo/seeds/20160624153032_add_things.exs

defmodule MyApp.Repo.Seeds.AddThings do
  use MyApp.Seed

  def up(_repo) do
    # seeding logic ...
  end
end
```

Execute the seed(s).

    $ mix phil_columns.seed

### The Seed Command

The simplest usage of the seed command defaults the environment to `dev` and the version to `all`.

    $ mix phil_columns.seed

The env can be overridden by providing a switch.  The env is used to select only seeds that have been
specified for the specified env.

    $ mix phil_columns.seed --env=prod
    $ mix phil_columns.seed -e prod

### Tags and Environments

Tags and environments can be applied to seeds and filtered in command usage.  The seed generator adds the `dev`
environment by default and no tags.  This feature enables efficiency and adaptability in development seeding and
the possibility to use _PhilColumns_ seeding in production (see Production Seeding section below).

Specifying environment(s) for a seed is accomplished with the envs function.

```elixir
defmodule MyApp.Repo.Seeds.AddThings do
  use MyApp.Seed

  envs [:dev, :prod]
  # ...
end
```

To change the environment use the env switch.  When not specified the env defaults to `dev`.

    $ mix phil_columns.seed -e prod

Similary, applying tag(s) is accomplished using the tags function.

```elixir
defmodule MyApp.Repo.Seeds.AddThings do
  use MyApp.Seed

  envs [:dev, :prod]
  tags [:some_tag]
  # ...
end
```

To change the tag(s) provide them after the command command line.

    $ mix phil_columns.seed --tags=users,settings,etc
    $ mix phil_columns.seed -t users,settings,etc


## Production Seeding

### Why?

Systems often have system level data that must be seeded when bootstraping a system or as new features are rolled out.  Some
examples are settings, configurations, roles, licenses, etc.

_PhilColumns_ provides the ability to apply these system data seedings and commit them with features, analgous to an Ecto
migration. Committing seed data with features or bug fixes communicates the intention of the data more clearly than any
other strategy can.

### How?

Create a module specifically for dealing with seeding in production.

```elixir
defmodule MyApp.Deployment.Seeder do
  import Mix.Ecto
  import Mix.PhilColumns

  def seed(opts, seeder \\ &PhilColumns.Seeder.run/4) do
    repos = parse_repo(opts)
            |> List.wrap

    # set env with current_env/0 overwriting provided arg
    opts = Keyword.put( opts, :env, current_env )

    opts =
      if opts[:to] || opts[:step] || opts[:all],
        do: opts,
        else: Keyword.put(opts, :all, true)

    opts =
      if opts[:log],
        do: opts,
        else: Keyword.put(opts, :log, :info)

    opts =
      if opts[:quiet],
        do: Keyword.put(opts, :log, false),
        else: opts

    Enum.each(repos, fn repo ->
      exec_task(repo, opts, fn ->
        seeder.(repo, seeds_path(repo), :up, opts)
      end)
    end)
  end

  defp current_env do
    # implement this
    # warning: do not use Mix.env if you are doing an erlang release
  end
end
```

Use the module in the production app's remote console.

```elixir
MyApp.Deployment.Seeder.seed(tags: ~w(things stuff)a)
```