Compare commits
8 commits
Author | SHA1 | Date | |
---|---|---|---|
James Harton | 85113e4ebd | ||
James Harton | 9f3248dbc9 | ||
James Harton | 15117cf1bb | ||
James Harton | f2df421786 | ||
James Harton | 408c813320 | ||
James Harton | ac2521c3c3 | ||
Renovate Bot | f6f473f753 | ||
Renovate Bot | 361bfad584 |
246
.drone.yml
246
.drone.yml
|
@ -26,7 +26,6 @@ steps:
|
|||
|
||||
- name: restore build cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
|
@ -73,7 +72,6 @@ steps:
|
|||
|
||||
- name: store ASDF cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
|
@ -97,7 +95,6 @@ steps:
|
|||
|
||||
- name: store build cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
|
@ -123,65 +120,8 @@ steps:
|
|||
- .mix
|
||||
- .rebar3
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: test
|
||||
|
||||
depends_on:
|
||||
- build
|
||||
|
||||
steps:
|
||||
- name: restore ASDF cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: SECRET_ACCESS_KEY
|
||||
AWS_PLUGIN_PATH_STYLE: true
|
||||
settings:
|
||||
restore: true
|
||||
endpoint:
|
||||
from_secret: S3_ENDPOINT
|
||||
bucket:
|
||||
from_secret: CACHE_BUCKET
|
||||
region: us-east-1
|
||||
path-style: true
|
||||
cache_key: 'asdf-{{ os }}-{{ arch }}-{{ checksum ".tool-versions" }}'
|
||||
mount:
|
||||
- .asdf
|
||||
|
||||
- name: restore build cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: SECRET_ACCESS_KEY
|
||||
AWS_PLUGIN_PATH_STYLE: true
|
||||
settings:
|
||||
restore: true
|
||||
endpoint:
|
||||
from_secret: S3_ENDPOINT
|
||||
bucket:
|
||||
from_secret: CACHE_BUCKET
|
||||
region: us-east-1
|
||||
path-style: true
|
||||
cache_key: 'elixir-{{ checksum "mix.lock" }}-{{ checksum ".tool-versions" }}'
|
||||
mount:
|
||||
- deps
|
||||
- _build
|
||||
- .hex
|
||||
- .mix
|
||||
- .rebar3
|
||||
|
||||
- name: mix compile
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -189,14 +129,12 @@ steps:
|
|||
REBAR_BASE_DIR: /drone/src/.rebar3
|
||||
ASDF_DATA_DIR: /drone/src/.asdf
|
||||
depends_on:
|
||||
- restore ASDF cache
|
||||
- restore build cache
|
||||
- install dependencies
|
||||
commands:
|
||||
- asdf mix compile --warnings-as-errors
|
||||
|
||||
- name: mix test
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -210,7 +148,6 @@ steps:
|
|||
|
||||
- name: mix credo
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -224,7 +161,6 @@ steps:
|
|||
|
||||
- name: mix hex.audit
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -238,7 +174,6 @@ steps:
|
|||
|
||||
- name: mix format
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -252,7 +187,6 @@ steps:
|
|||
|
||||
- name: mix spark.formatter
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -266,7 +200,6 @@ steps:
|
|||
|
||||
- name: mix deps.unlock
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -280,7 +213,6 @@ steps:
|
|||
|
||||
- name: mix doctor
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -294,7 +226,6 @@ steps:
|
|||
|
||||
- name: mix git_ops.check_message
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -307,73 +238,20 @@ steps:
|
|||
- git log -1 --format=%s > .last_commit_message
|
||||
- asdf mix git_ops.check_message .last_commit_message
|
||||
|
||||
---
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: git ops
|
||||
|
||||
trigger:
|
||||
branch:
|
||||
- main
|
||||
event:
|
||||
- push
|
||||
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
steps:
|
||||
- name: restore ASDF cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: SECRET_ACCESS_KEY
|
||||
AWS_PLUGIN_PATH_STYLE: true
|
||||
settings:
|
||||
restore: true
|
||||
endpoint:
|
||||
from_secret: S3_ENDPOINT
|
||||
bucket:
|
||||
from_secret: CACHE_BUCKET
|
||||
region: us-east-1
|
||||
path-style: true
|
||||
cache_key: 'asdf-{{ os }}-{{ arch }}-{{ checksum ".tool-versions" }}'
|
||||
mount:
|
||||
- .asdf
|
||||
|
||||
- name: restore build cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: SECRET_ACCESS_KEY
|
||||
AWS_PLUGIN_PATH_STYLE: true
|
||||
settings:
|
||||
restore: true
|
||||
endpoint:
|
||||
from_secret: S3_ENDPOINT
|
||||
bucket:
|
||||
from_secret: CACHE_BUCKET
|
||||
region: us-east-1
|
||||
path-style: true
|
||||
cache_key: 'elixir-{{ checksum "mix.lock" }}-{{ checksum ".tool-versions" }}'
|
||||
mount:
|
||||
- deps
|
||||
- _build
|
||||
- .hex
|
||||
- .mix
|
||||
- .rebar3
|
||||
|
||||
- name: mix git_ops.release
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
when:
|
||||
branch:
|
||||
- main
|
||||
depends_on:
|
||||
- restore ASDF cache
|
||||
- restore build cache
|
||||
- mix test
|
||||
- mix credo
|
||||
- mix hex.audit
|
||||
- mix format
|
||||
- mix spark.formatter
|
||||
- mix deps.unlock
|
||||
- mix doctor
|
||||
- mix git_ops.check_message
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -398,73 +276,23 @@ steps:
|
|||
- git push $${GIT_URL} "HEAD:${DRONE_COMMIT_REF}" "refs/tags/v$${NEW_APP_VERSION}"
|
||||
- fi
|
||||
|
||||
---
|
||||
|
||||
kind: pipeline
|
||||
type: docker
|
||||
name: release
|
||||
|
||||
trigger:
|
||||
ref:
|
||||
include:
|
||||
- refs/tags/v**
|
||||
|
||||
depends_on:
|
||||
- test
|
||||
|
||||
steps:
|
||||
- name: restore ASDF cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: SECRET_ACCESS_KEY
|
||||
AWS_PLUGIN_PATH_STYLE: true
|
||||
settings:
|
||||
restore: true
|
||||
endpoint:
|
||||
from_secret: S3_ENDPOINT
|
||||
bucket:
|
||||
from_secret: CACHE_BUCKET
|
||||
region: us-east-1
|
||||
path-style: true
|
||||
cache_key: 'asdf-{{ os }}-{{ arch }}-{{ checksum ".tool-versions" }}'
|
||||
mount:
|
||||
- .asdf
|
||||
|
||||
- name: restore build cache
|
||||
image: meltwater/drone-cache
|
||||
pull: "always"
|
||||
environment:
|
||||
AWS_ACCESS_KEY_ID:
|
||||
from_secret: ACCESS_KEY_ID
|
||||
AWS_SECRET_ACCESS_KEY:
|
||||
from_secret: SECRET_ACCESS_KEY
|
||||
AWS_PLUGIN_PATH_STYLE: true
|
||||
settings:
|
||||
restore: true
|
||||
endpoint:
|
||||
from_secret: S3_ENDPOINT
|
||||
bucket:
|
||||
from_secret: CACHE_BUCKET
|
||||
region: us-east-1
|
||||
path-style: true
|
||||
cache_key: 'elixir-{{ checksum "mix.lock" }}-{{ checksum ".tool-versions" }}'
|
||||
mount:
|
||||
- deps
|
||||
- _build
|
||||
- .hex
|
||||
- .mix
|
||||
- .rebar3
|
||||
|
||||
- name: build artifacts
|
||||
image: code.harton.nz/james/asdf_container:latest
|
||||
pull: "always"
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
refs:
|
||||
include:
|
||||
- refs/tags/v*
|
||||
depends_on:
|
||||
- restore ASDF cache
|
||||
- restore build cache
|
||||
- mix test
|
||||
- mix credo
|
||||
- mix hex.audit
|
||||
- mix format
|
||||
- mix spark.formatter
|
||||
- mix deps.unlock
|
||||
- mix doctor
|
||||
- mix git_ops.check_message
|
||||
environment:
|
||||
MIX_ENV: test
|
||||
HEX_HOME: /drone/src/.hex
|
||||
|
@ -477,7 +305,6 @@ steps:
|
|||
- mix git_ops.project_info --format=shell > app.env
|
||||
- . ./app.env
|
||||
- mkdir artifacts
|
||||
- mix esbuild prod
|
||||
- mix hex.build -o "artifacts/$${APP_NAME}-$${APP_VERSION}-pkg.tar"
|
||||
- gzip "artifacts/$${APP_NAME}-$${APP_VERSION}-pkg.tar"
|
||||
- mix docs
|
||||
|
@ -487,6 +314,12 @@ steps:
|
|||
|
||||
- name: gitea release
|
||||
image: plugins/gitea-release
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
refs:
|
||||
include:
|
||||
- refs/tags/v*
|
||||
depends_on:
|
||||
- build artifacts
|
||||
settings:
|
||||
|
@ -499,6 +332,12 @@ steps:
|
|||
note: tag_body
|
||||
|
||||
- name: docs release
|
||||
when:
|
||||
event:
|
||||
- tag
|
||||
refs:
|
||||
include:
|
||||
- refs/tags/v*
|
||||
image: minio/mc
|
||||
environment:
|
||||
S3_ENDPOINT:
|
||||
|
@ -519,9 +358,14 @@ steps:
|
|||
# - name: hex release
|
||||
# image: code.harton.nz/james/asdf_container:latest
|
||||
# pull: "always"
|
||||
# when:
|
||||
# event:
|
||||
# - tag
|
||||
# refs:
|
||||
# include:
|
||||
# - refs/tags/v*
|
||||
# depends_on:
|
||||
# - restore ASDF cache
|
||||
# - restore build cache
|
||||
# - build artifacts
|
||||
# environment:
|
||||
# MIX_ENV: test
|
||||
# HEX_HOME: /drone/src/.hex
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
elixir 1.15.4-otp-26
|
||||
elixir 1.15.4
|
||||
erlang 26.0.2
|
||||
|
|
13
CHANGELOG.md
13
CHANGELOG.md
|
@ -5,6 +5,19 @@ See [Conventional Commits](Https://conventionalcommits.org) for commit guideline
|
|||
|
||||
<!-- changelog -->
|
||||
|
||||
## [v0.1.1](https://code.harton.nz/james/smokestack/compare/v0.1.0...v0.1.1) (2023-08-18)
|
||||
|
||||
|
||||
|
||||
|
||||
### Improvements:
|
||||
|
||||
* Add `insert_many`.
|
||||
|
||||
* Add `Smokestack` behaviour.
|
||||
|
||||
* Add `Builder.insert/2..5`.
|
||||
|
||||
## [v0.1.0](https://code.harton.nz/james/smokestack/compare/v0.1.0...v0.1.0) (2023-08-16)
|
||||
|
||||
|
||||
|
|
9
config/config.exs
Normal file
9
config/config.exs
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Config
|
||||
|
||||
config :git_ops,
|
||||
mix_project: Mix.Project.get!(),
|
||||
changelog_file: "CHANGELOG.md",
|
||||
repository_url: "https://code.harton.nz/james/smokestack",
|
||||
manage_mix_version?: true,
|
||||
version_tag_prefix: "v",
|
||||
manage_readme_version: "README.md"
|
|
@ -19,6 +19,144 @@ defmodule Smokestack do
|
|||
"""
|
||||
|
||||
use Dsl, default_extensions: [extensions: [Smokestack.Dsl]]
|
||||
alias Ash.Resource
|
||||
alias Smokestack.Builder
|
||||
|
||||
@type t :: module
|
||||
|
||||
@doc """
|
||||
Runs a factory and uses it to build a map or list of results.
|
||||
|
||||
Automatically implemented by modules which `use Smokestack`.
|
||||
|
||||
See `Smokestack.Builder.params/5` for more information.
|
||||
"""
|
||||
@callback params(Resource.t(), map, atom, Builder.param_options()) ::
|
||||
{:ok, Builder.param_result()} | {:error, any}
|
||||
|
||||
@doc """
|
||||
Raising version of `params/4`.
|
||||
|
||||
Automatically implemented by modules which `use Smokestack`.
|
||||
|
||||
See `Smokestack.Builder.params/5` for more information.
|
||||
"""
|
||||
@callback params!(Resource.t(), map, atom, Builder.param_options()) ::
|
||||
Builder.param_result() | no_return
|
||||
|
||||
@doc """
|
||||
Runs a factory and uses it to insert an Ash Resource into it's data layer.
|
||||
|
||||
Automatically implemented by modules which `use Smokestack`.
|
||||
|
||||
See `Smokestack.Builder.insert/5` for more information.
|
||||
"""
|
||||
@callback insert(Resource.t(), map, atom, Builder.insert_options()) ::
|
||||
{:ok, Resource.record()} | {:error, any}
|
||||
|
||||
@doc """
|
||||
Raising version of `insert/4`.
|
||||
|
||||
Automatically implemented by modules which `use Smokestack`.
|
||||
|
||||
See `Smokestack.Builder.insert/5` for more information.
|
||||
"""
|
||||
@callback insert!(Resource.t(), map, atom, Builder.insert_options()) ::
|
||||
Resource.record() | no_return
|
||||
|
||||
@doc """
|
||||
Runs a factory a number of times and returns a list of created records.
|
||||
|
||||
Automatically implemented by modules which `use Smokestack`.
|
||||
|
||||
See `Smokestack.Builder.insert_many/5` for more information.
|
||||
"""
|
||||
@callback insert_many(Resource.t(), pos_integer, atom, Builder.insert_options()) ::
|
||||
{:ok, [Resource.record()]} | {:error, any}
|
||||
|
||||
@doc """
|
||||
Raising version of `insert_many/4`.
|
||||
|
||||
Automatically implemented by modules which `use Smokestack`.
|
||||
|
||||
See `Smokestack.Builder.insert_many/5` for more information.
|
||||
"""
|
||||
@callback insert_many!(Resource.t(), pos_integer, atom, Builder.insert_options()) ::
|
||||
[Resource.record()] | no_return
|
||||
|
||||
@doc false
|
||||
defmacro __using__(opts) do
|
||||
[
|
||||
quote do
|
||||
@behaviour Smokestack
|
||||
|
||||
@doc """
|
||||
Execute the matching factory and return a map or list of params.
|
||||
|
||||
See `Smokestack.Builder.params/5` for more information.
|
||||
"""
|
||||
@spec params(Resource.t(), map, atom, Builder.param_options()) ::
|
||||
{:ok, Builder.param_result()} | {:error, any}
|
||||
def params(resource, overrides \\ %{}, variant \\ :default, options \\ []),
|
||||
do: Builder.params(__MODULE__, resource, overrides, variant, options)
|
||||
|
||||
@doc """
|
||||
Raising version of `params/4`.
|
||||
|
||||
See `Smokestack.Builder.params/5` for more information.
|
||||
"""
|
||||
@spec params!(Resource.t(), map, atom, Builder.param_options()) ::
|
||||
Builder.param_result() | no_return
|
||||
def params!(resource, overrides \\ %{}, variant \\ :default, options \\ []),
|
||||
do: Builder.params!(__MODULE__, resource, overrides, variant, options)
|
||||
|
||||
@doc """
|
||||
Execute the matching factory and return an inserted Ash Resource record.
|
||||
|
||||
See `Smokestack.Builder.insert/5` for more information.
|
||||
"""
|
||||
@spec insert(Resource.t(), map, atom, Builder.insert_options()) ::
|
||||
{:ok, Resource.record()} | {:error, any}
|
||||
def insert(resource, overrides \\ %{}, variant \\ :default, options \\ []),
|
||||
do: Builder.insert(__MODULE__, resource, overrides, variant, options)
|
||||
|
||||
@doc """
|
||||
Raising version of `insert/4`.
|
||||
|
||||
See `Smokestack.Builder.insert/5` for more information.
|
||||
"""
|
||||
@spec insert!(Resource.t(), map, atom, Builder.insert_options()) ::
|
||||
Resource.record() | no_return
|
||||
def insert!(resource, overrides \\ %{}, variant \\ :default, options \\ []),
|
||||
do: Builder.insert!(__MODULE__, resource, overrides, variant, options)
|
||||
|
||||
@doc """
|
||||
Execute the matching factory a number of times and return a list of Ash Resource records.
|
||||
|
||||
See `Smokestack.Builder.insert_many/5` for more information.
|
||||
"""
|
||||
@spec insert_many(Resource.t(), pos_integer, atom, Builder.insert_options()) ::
|
||||
{:ok, [Resource.record()]} | {:error, any}
|
||||
def insert_many(resource, count, variant \\ :default, options \\ []),
|
||||
do: Builder.insert_many(__MODULE__, resource, count, variant, options)
|
||||
|
||||
@doc """
|
||||
Raising version of `insert_many/4`.
|
||||
|
||||
See `Smokestack.Builder.insert_many/5` for more information.
|
||||
"""
|
||||
@spec insert_many!(Resource.t(), pos_integer, atom, Builder.insert_options()) ::
|
||||
[Resource.record()] | no_return
|
||||
def insert_many!(resource, count, variant \\ :default, options \\ []),
|
||||
do: Builder.insert_many!(__MODULE__, resource, count, variant, options)
|
||||
|
||||
defoverridable params: 4,
|
||||
params!: 4,
|
||||
insert: 4,
|
||||
insert!: 4,
|
||||
insert_many: 4,
|
||||
insert_many!: 4
|
||||
end
|
||||
] ++ super(opts)
|
||||
end
|
||||
end
|
||||
|
|
|
@ -3,13 +3,13 @@ defmodule Smokestack.Builder do
|
|||
Handles the building of parameters and records.
|
||||
"""
|
||||
|
||||
alias Ash.Resource
|
||||
alias Ash.{Resource, Seed}
|
||||
alias Smokestack.{Dsl.Attribute, Dsl.Info, Template}
|
||||
|
||||
@param_option_defaults [keys: :atom, as: :map]
|
||||
|
||||
@typedoc "Options that can be passed to `params/4`."
|
||||
@type param_options :: [param_keys_option | param_as_option]
|
||||
@type param_options :: [param_keys_option | param_as_option | build_option]
|
||||
|
||||
@typedoc "Key type in the result. Defaults to `#{inspect(@param_option_defaults[:keys])}`."
|
||||
@type param_keys_option :: {:keys, :atom | :string | :dasherise}
|
||||
|
@ -18,17 +18,22 @@ defmodule Smokestack.Builder do
|
|||
@type param_as_option :: {:as, :map | :list}
|
||||
|
||||
@type param_result ::
|
||||
%{required(String.t()) => any}
|
||||
| %{required(atom) => any}
|
||||
| [{String.t(), any}]
|
||||
| [{atom, any}]
|
||||
%{required(atom | String.t()) => any}
|
||||
| [{atom | String.t(), any}]
|
||||
|
||||
@type insert_options :: [build_option]
|
||||
|
||||
@typedoc "A nested keyword list of associations that should also be built"
|
||||
@type build_option :: {:build, Keyword.t(atom | Keyword.t())}
|
||||
|
||||
@type insert_result :: Resource.record()
|
||||
|
||||
@doc """
|
||||
Build parameters for a resource with a factory.
|
||||
"""
|
||||
@spec params(Smokestack.t(), Resource.t(), atom, param_options) ::
|
||||
@spec params(Smokestack.t(), Resource.t(), map, atom, param_options) ::
|
||||
{:ok, param_result} | {:error, any}
|
||||
def params(factory_module, resource, variant \\ :default, overrides \\ %{}, options \\ [])
|
||||
def params(factory_module, resource, overrides \\ %{}, variant \\ :default, options \\ [])
|
||||
when is_atom(factory_module) and is_atom(resource) and is_atom(variant) and is_list(options) do
|
||||
with {:ok, factory} <- get_factory(factory_module, resource, variant),
|
||||
{:ok, params} <- build_params(factory, overrides, options) do
|
||||
|
@ -43,14 +48,107 @@ defmodule Smokestack.Builder do
|
|||
end
|
||||
|
||||
@doc "Raising version of `params/2..5`."
|
||||
@spec params!(Smokestack.t(), Resource.t(), atom, param_options) :: param_result | no_return
|
||||
def params!(factory_module, resource, variant \\ :default, overrides \\ %{}, options \\ []) do
|
||||
case params(factory_module, resource, variant, overrides, options) do
|
||||
@spec params!(Smokestack.t(), Resource.t(), map, atom, param_options) ::
|
||||
param_result | no_return
|
||||
def params!(factory_module, resource, overrides \\ %{}, variant \\ :default, options \\ []) do
|
||||
case params(factory_module, resource, overrides, variant, options) do
|
||||
{:ok, params} -> params
|
||||
{:error, reason} -> raise reason
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Build a resource and insert it into it's datalayer.
|
||||
"""
|
||||
@spec insert(Smokestack.t(), Resource.t(), map, atom, insert_options) ::
|
||||
{:ok, insert_result} | {:error, any}
|
||||
def insert(factory_module, resource, overrides \\ %{}, variant \\ :default, options \\ [])
|
||||
when is_atom(factory_module) and is_atom(resource) and is_atom(Variant) and is_list(options) do
|
||||
with {:ok, factory} <- get_factory(factory_module, resource, variant),
|
||||
{:ok, params} <- build_params(factory, overrides, options) do
|
||||
record =
|
||||
resource
|
||||
|> Seed.seed!(params)
|
||||
|> Resource.put_metadata(:factory, factory_module)
|
||||
|> Resource.put_metadata(:variant, variant)
|
||||
|
||||
{:ok, record}
|
||||
end
|
||||
rescue
|
||||
error -> {:error, error}
|
||||
end
|
||||
|
||||
@doc "Raising version of `insert/2..5`"
|
||||
@spec insert!(Smokestack.t(), Resource.t(), map, atom, insert_options) ::
|
||||
insert_result | no_return
|
||||
def insert!(factory_module, resource, overrides \\ %{}, variant \\ :default, options \\ [])
|
||||
when is_atom(factory_module) and is_atom(resource) and is_atom(variant) and
|
||||
is_map(overrides) and is_list(options) do
|
||||
with {:ok, factory} <- get_factory(factory_module, resource, variant),
|
||||
{:ok, params} <- build_params(factory, overrides, options) do
|
||||
resource
|
||||
|> Seed.seed!(params)
|
||||
|> Resource.put_metadata(:factory, factory_module)
|
||||
|> Resource.put_metadata(:variant, variant)
|
||||
else
|
||||
{:error, reason} -> raise reason
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Build a number of resources and insert them into their datalayer.
|
||||
"""
|
||||
@spec insert_many(Smokestack.t(), Resource.t(), pos_integer, atom, insert_options) ::
|
||||
{:ok, [insert_result]} | {:error, any}
|
||||
def insert_many(factory_module, resource, count, variant \\ :default, options \\ [])
|
||||
when is_atom(factory_module) and is_atom(resource) and is_integer(count) and count > 0 and
|
||||
is_atom(variant) and is_list(options) do
|
||||
with {:ok, factory} <- get_factory(factory_module, resource, variant),
|
||||
{:ok, params_list} <- build_many_params(factory, count, options) do
|
||||
records =
|
||||
resource
|
||||
|> Seed.seed!(params_list)
|
||||
|> Enum.map(fn record ->
|
||||
record
|
||||
|> Resource.put_metadata(:factory, factory_module)
|
||||
|> Resource.put_metadata(:variant, variant)
|
||||
end)
|
||||
|
||||
{:ok, records}
|
||||
end
|
||||
rescue
|
||||
error -> {:error, error}
|
||||
end
|
||||
|
||||
@doc "Raising version of `insert_many/5`."
|
||||
@spec insert_many!(Smokestack.t(), Resource.t(), pos_integer, atom, insert_options) ::
|
||||
[insert_result] | no_return
|
||||
def insert_many!(factory_module, resource, count, variant \\ :default, options \\ [])
|
||||
when is_atom(factory_module) and is_atom(resource) and is_integer(count) and count > 0 and
|
||||
is_atom(variant) and is_list(options) do
|
||||
with {:ok, factory} <- get_factory(factory_module, resource, variant),
|
||||
{:ok, params_list} <- build_many_params(factory, count, options) do
|
||||
resource
|
||||
|> Seed.seed!(params_list)
|
||||
|> Enum.map(fn record ->
|
||||
record
|
||||
|> Resource.put_metadata(:factory, factory_module)
|
||||
|> Resource.put_metadata(:variant, variant)
|
||||
end)
|
||||
else
|
||||
{:error, reason} -> raise reason
|
||||
end
|
||||
end
|
||||
|
||||
defp build_many_params(factory, count, options) do
|
||||
Enum.reduce_while(1..count, {:ok, []}, fn _, {:ok, params_list} ->
|
||||
case build_params(factory, %{}, options) do
|
||||
{:ok, params} -> {:cont, {:ok, [params | params_list]}}
|
||||
{:error, reason} -> {:halt, {:error, reason}}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp get_factory(factory_module, resource, variant) do
|
||||
with :error <- Info.factory(factory_module, resource, variant) do
|
||||
{:error,
|
||||
|
@ -70,15 +168,24 @@ defmodule Smokestack.Builder do
|
|||
{:ok, Map.put(attrs, attr.name, override)}
|
||||
|
||||
:error ->
|
||||
value = Template.generate(attr.generator, attrs, options)
|
||||
generator = maybe_initialise_generator(attr)
|
||||
value = Template.generate(generator, attrs, options)
|
||||
{:ok, Map.put(attrs, attr.name, value)}
|
||||
end
|
||||
end)
|
||||
end
|
||||
|
||||
defp maybe_initialise_generator(attr) do
|
||||
with nil <- Process.get(attr.__identifier__),
|
||||
generator <- Template.init(attr.generator) do
|
||||
Process.put(attr.__identifier__, generator)
|
||||
generator
|
||||
end
|
||||
end
|
||||
|
||||
defp maybe_stringify_keys(attrs, options) do
|
||||
if Keyword.get(options, :keys, @param_option_defaults[:keys]) == :string do
|
||||
Map.new(fn {key, value} -> {Atom.to_string(key), value} end)
|
||||
Map.new(attrs, fn {key, value} -> {Atom.to_string(key), value} end)
|
||||
else
|
||||
attrs
|
||||
end
|
||||
|
@ -86,7 +193,7 @@ defmodule Smokestack.Builder do
|
|||
|
||||
defp maybe_dasherise_keys(attrs, options) do
|
||||
if Keyword.get(options, :keys, @param_option_defaults[:keys]) == :dasherise do
|
||||
Map.new(fn {key, value} ->
|
||||
Map.new(attrs, fn {key, value} ->
|
||||
key =
|
||||
key
|
||||
|> Atom.to_string()
|
||||
|
|
|
@ -5,12 +5,13 @@ defmodule Smokestack.Dsl.Attribute do
|
|||
See `d:Smokestack.factory.default.attribute` for more information.
|
||||
"""
|
||||
|
||||
defstruct generator: nil, name: nil
|
||||
defstruct __identifier__: nil, generator: nil, name: nil
|
||||
|
||||
alias Ash.Resource
|
||||
alias Spark.Dsl.Entity
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
__identifier__: nil,
|
||||
generator:
|
||||
mfa | (-> any) | (Resource.record() -> any) | (Resource.record(), keyword -> any),
|
||||
name: atom
|
||||
|
@ -24,6 +25,7 @@ defmodule Smokestack.Dsl.Attribute do
|
|||
name: :attribute,
|
||||
target: __MODULE__,
|
||||
args: [:name, :generator],
|
||||
identifier: {:auto, :unique_integer},
|
||||
schema: [
|
||||
name: [
|
||||
type: :atom,
|
||||
|
|
|
@ -5,13 +5,14 @@ defmodule Smokestack.Dsl.Factory do
|
|||
See `d:Smokestack.factory` for more information.
|
||||
"""
|
||||
|
||||
defstruct attributes: [], resource: nil, variant: :default
|
||||
defstruct __identifier__: nil, attributes: [], resource: nil, variant: :default
|
||||
|
||||
alias Ash.Resource
|
||||
alias Smokestack.Dsl.{Attribute, Template}
|
||||
alias Spark.Dsl.Entity
|
||||
|
||||
@type t :: %__MODULE__{
|
||||
__identifier__: any,
|
||||
attributes: [Attribute.t()],
|
||||
resource: Resource.t(),
|
||||
variant: atom
|
||||
|
@ -27,6 +28,7 @@ defmodule Smokestack.Dsl.Factory do
|
|||
target: __MODULE__,
|
||||
args: [:resource, {:optional, :variant, :default}],
|
||||
imports: [Template],
|
||||
identifier: {:auto, :unique_integer},
|
||||
schema: [
|
||||
resource: [
|
||||
type: {:behaviour, Ash.Resource},
|
||||
|
|
2
mix.exs
2
mix.exs
|
@ -1,7 +1,7 @@
|
|||
defmodule Smokestack.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
@version "0.1.0"
|
||||
@version "0.1.1"
|
||||
|
||||
@moduledoc """
|
||||
Test factories for Ash resources.
|
||||
|
|
6
renovate.json
Normal file
6
renovate.json
Normal file
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"$schema": "https://docs.renovatebot.com/renovate-schema.json",
|
||||
"extends": [
|
||||
"local>renovate/renovate"
|
||||
]
|
||||
}
|
|
@ -8,10 +8,47 @@ defmodule Smokestack.BuilderTest do
|
|||
describe "params/2..5" do
|
||||
test "it builds params" do
|
||||
assert {:ok, params} = Builder.params(Factory, Post)
|
||||
assert params |> Map.keys() |> Enum.sort() == ~w[body tags title]a
|
||||
assert params |> Map.keys() |> Enum.sort() == ~w[body sub_title tags title]a
|
||||
assert is_binary(params.body)
|
||||
assert Enum.all?(params.tags, &is_binary/1)
|
||||
assert is_binary(params.title)
|
||||
end
|
||||
|
||||
test "it honours the `as: :list` option" do
|
||||
assert {:ok, params} = Builder.params(Factory, Post, %{}, :default, as: :list)
|
||||
assert is_list(params)
|
||||
assert is_binary(params[:body])
|
||||
assert Enum.all?(params[:tags], &is_binary/1)
|
||||
assert is_binary(params[:title])
|
||||
end
|
||||
|
||||
test "it honours the `keys: :string` option" do
|
||||
assert {:ok, params} = Builder.params(Factory, Post, %{}, :default, keys: :string)
|
||||
assert is_binary(params["body"])
|
||||
assert Enum.all?(params["tags"], &is_binary/1)
|
||||
assert is_binary(params["title"])
|
||||
end
|
||||
|
||||
test "it honours the `keys: :dasherise` option" do
|
||||
assert {:ok, params} = Builder.params(Factory, Post, %{}, :default, keys: :dasherise)
|
||||
assert is_binary(params["sub-title"])
|
||||
end
|
||||
end
|
||||
|
||||
describe "insert/2..5" do
|
||||
test "it inserts the resource" do
|
||||
assert {:ok, record} = Builder.insert(Factory, Post)
|
||||
assert is_struct(record, Post)
|
||||
assert record.inserted_at
|
||||
assert is_binary(record.title)
|
||||
assert is_binary(record.sub_title)
|
||||
assert Enum.all?(record.tags, &is_struct(&1, Ash.CiString))
|
||||
end
|
||||
end
|
||||
|
||||
describe "insert_many/3..5" do
|
||||
assert {:ok, records} = Builder.insert_many(Factory, Post, 3)
|
||||
assert length(records) == 3
|
||||
assert Enum.all?(records, &is_struct(&1, Post))
|
||||
end
|
||||
end
|
||||
|
|
|
@ -23,6 +23,7 @@ defmodule Support.Factory do
|
|||
attribute :title, &Faker.Commerce.product_name/0
|
||||
attribute :tags, n_times(3..20, &Faker.Lorem.word/0)
|
||||
attribute :body, &Faker.Markdown.markdown/0
|
||||
attribute :sub_title, &Faker.Lorem.sentence/0
|
||||
end
|
||||
|
||||
factory Support.Post, :trek do
|
||||
|
|
Loading…
Reference in a new issue