8 Commits

Author SHA1 Message Date
Joao P Dubas
6bf5e51493 chore: minor change in lock file
All checks were successful
continuous-integration/drone/pr Build is passing
2022-04-25 14:15:21 +00:00
Joao P Dubas
6ee89e38b4 fix: spec for serialize_range method 2022-04-25 14:13:58 +00:00
Joao P Dubas
fa674ceb36 chore: add lint step
In this step we check:

1. format
2. credo
3. dialyzer
2022-04-25 13:50:58 +00:00
Joao P Dubas
d22d93ed6c wip: set custom cache key 2022-04-25 13:50:58 +00:00
Joao P Dubas
f37942da6f wip: pin drone-cache version 2022-04-25 13:50:58 +00:00
Joao P Dubas
afface5808 fix: fail silently when restoring cache 2022-04-25 13:50:58 +00:00
Joao P Dubas
4aea4ffc75 wip: experiment with drone cache
Try to make builds faster
2022-04-25 13:50:58 +00:00
Joao P Dubas
372083a9ee chore: remove github actions
We're sticking with drone for now.
2022-04-25 13:50:58 +00:00
29 changed files with 256 additions and 657 deletions

View File

@@ -1,33 +0,0 @@
.dockerignore
docker-compose.yml
docker-compose.*.yml
# Ignore git, but keep git HEAD and refs to access current commit hash if needed:
#
# $ cat .git/HEAD | awk '{print ".git/"$2}' | xargs cat
# d0b8727759e1e0e7aa3d41707d12376e373d5ecc
.git
!.git/HEAD
!.git/refs
# Common development/test artifacts
/cover/
/doc/
/test/
/tmp/
/.elixir_ls
/.elixir-tools/
# Mix artifacts
/_build/
/deps/
*.ez
# Generated on crash by the VM
erl_crash.dump
# Static artifacts - These should be fetched and built inside the Docker image
/assets/node_modules/
/priv/plts/
/priv/static/assets/
/priv/static/cache_manifest.json

View File

@@ -1,190 +1,75 @@
--- ---
kind: pipeline kind: pipeline
type: docker type: docker
name: test and lint name: test
trigger: trigger:
branch: event:
- main - pull_request
steps: steps:
- name: database healthcheck - name: database healthcheck
image: &postgres 'postgres:17.0-alpine' image: 'postgres:14.2-alpine'
environment: environment:
PGUSER: &db_user postgres PGUSER: postgres
PGPASSWORD: &db_pass postgres PGPASSWORD: postgres
PGHOST: &db_host db PGHOST: db
commands: commands:
- while ! pg_isready; do sleep 1; done - while ! pg_isready; do sleep 1; done
depends_on:
- 'db'
- name: restore cache - name: restore cache
image: &drone_cache 'meltwater/drone-cache:v1.4.0' image: 'meltwater/drone-cache:v1.3.0'
environment:
AWS_ACCESS_KEY_ID:
from_secret: minio_user
AWS_SECRET_ACCESS_KEY:
from_secret: minio_password
settings: settings:
archive_format: gzip archive_format: gzip
bucket: trainlog-cache backend: filesystem
cache_key: '{{ .Repo.Name }}-{{ checksum ".tool-versions" }}-{{ checksum "mix.lock" }}' cache_key: '{{ .Repo.Name }}-{{ checksum "mix.lock" }}'
endpoint: minio:9000
mount: mount:
- _build - _build
- deps - deps
path_style: true
region: us-east-1
restore: true restore: true
volumes: &volumes volumes:
- name: app_build - name: cache
path: /drone/src/_build path: /tmp/cache
- name: app_deps
path: /drone/src/deps
- name: docker_sock
path: /var/run/docker.sock
- name: dependencies and compile
image: &elixir 'hexpm/elixir:1.17.3-erlang-27.1.1-debian-bookworm-20240926-slim'
commands:
- apt-get update
- apt-get install -y git make
- mix do local.rebar --force, local.hex --force, deps.get, deps.compile
- mix compile --force --all-warnings --warnings-as-errors
volumes: *volumes
depends_on:
- 'restore cache'
- name: test - name: test
image: *elixir image: 'elixir:1.13.4'
environment: environment:
MIX_ENV: test MIX_ENV: test
POSTGRES_HOST: *db_host POSTGRES_HOST: db
POSTGRES_USER: *db_user POSTGRES_USER: postgres
POSTGRES_PASS: *db_pass POSTGRES_PASS: postgres
commands: commands:
- apt-get update - mix do local.rebar --force, local.hex --force, deps.get, deps.compile
- apt-get install -y git make - make test
- mix do local.rebar --force, local.hex --force
- mix test --cover --trace --slowest 10
volumes: *volumes
depends_on:
- 'database healthcheck'
- 'dependencies and compile'
- name: testcontainer - name: lint
image: *elixir image: 'elixir:1.13.4'
environment:
MIX_ENV: test
commands: commands:
- apt-get update - mix do local.rebar --force, local.hex --force, deps.get, deps.compile
- apt-get install -y git make - make static_code_analysis
- mix do local.rebar --force, local.hex --force
- mix testcontainers.test
volumes: *volumes
depends_on:
- 'dependencies and compile'
- name: audit deps
image: *elixir
commands:
- apt-get update
- apt-get install -y git make
- mix do local.rebar --force, local.hex --force
- mix hex.audit
- mix deps.audit
- mix deps.unlock --check-unused
# - mix hex.outdated
volumes: *volumes
depends_on:
- 'dependencies and compile'
- name: format check
image: *elixir
commands:
- apt-get update
- apt-get install -y git make
- mix do local.rebar --force, local.hex --force
- mix format --dry-run --check-formatted
volumes: *volumes
depends_on:
- 'dependencies and compile'
- name: credo check
image: *elixir
commands:
- apt-get update
- apt-get install -y git make
- mix do local.rebar --force, local.hex --force
- mix credo suggest --strict --format=flycheck
volumes: *volumes
depends_on:
- 'dependencies and compile'
- name: dialyzer check
image: *elixir
commands:
- apt-get update
- apt-get install -y git make
- mix do local.rebar --force, local.hex --force
- mix dialyzer --no-check --quiet --ignore-exit-status --format short
volumes: *volumes
depends_on:
- 'dependencies and compile'
- name: sobelow check
image: *elixir
commands:
- apt-get update
- apt-get install -y git make
- mix do local.rebar --force, local.hex --force
- mix sobelow
volumes: *volumes
depends_on:
- 'dependencies and compile'
- name: rebuild cache - name: rebuild cache
image: *drone_cache image: 'meltwater/drone-cache:v1.3.0'
environment:
AWS_ACCESS_KEY_ID:
from_secret: minio_user
AWS_SECRET_ACCESS_KEY:
from_secret: minio_password
settings: settings:
archive_format: gzip archive_format: gzip
bucket: trainlog-cache backend: filesystem
cache_key: '{{ .Repo.Name }}-{{ checksum ".tool-versions" }}-{{ checksum "mix.lock" }}' cache_key: '{{ .Repo.Name }}-{{ checksum "mix.lock" }}'
endpoint: minio:9000
exit_code: true
mount: mount:
- _build - _build
- deps - deps
path_style: true
rebuild: true rebuild: true
region: us-east-1 exit_code: true
volumes: *volumes volumes:
depends_on: - name: cache
- 'test' path: /tmp/cache
- 'audit deps'
- 'format check'
- 'credo check'
- 'dialyzer check'
- 'sobelow check'
services: services:
- name: *db_host - name: db
image: *postgres image: 'postgres:14.2-alpine'
environment: environment:
POSTGRES_USER: *db_user POSTGRES_USER: postgres
POSTGRES_PASSWORD: *db_pass POSTGRES_PASSWORD: postgres
volumes: volumes:
- name: app_build - name: cache
temp: {} temp: {}
- name: app_deps
temp: {}
- name: docker_sock
host:
path: /var/run/docker.sock

6
.gitignore vendored
View File

@@ -1,6 +1,4 @@
# paths # paths
/.elixir_ls/
/.elixir-tools/
/_build/ /_build/
/cover/ /cover/
/report/ /report/
@@ -15,5 +13,5 @@ erl_crash.dump
*.ez *.ez
wabanex-*.tar wabanex-*.tar
docker-compose.*.yml docker-compose.*.yml
/priv/docker/pgcli/history priv/docker/pgcli/history
/priv/docker/pgcli/log priv/docker/pgcli/log

View File

@@ -1,2 +1,2 @@
erlang 27.1.1 erlang 24.3.3
elixir 1.17.3 elixir 1.13.4-otp-24

View File

@@ -1,70 +0,0 @@
ARG ELIXIR_VERSION=1.17.3
ARG OTP_VERSION=27.1.1
ARG DEBIAN_VERSION=bookworm-20240926-slim
ARG BUILDER_IMAGE="hexpm/elixir:${ELIXIR_VERSION}-erlang-${OTP_VERSION}-debian-${DEBIAN_VERSION}"
ARG RUNNER_IMAGE="debian:${DEBIAN_VERSION}"
FROM ${BUILDER_IMAGE} AS builder
RUN apt-get update \
&& apt-get -y install \
build-essential \
git \
make \
&& apt-get clean \
&& rm -rf /var/lib/ap/lists/*_*
WORKDIR /opt/app
# install hex + rebar
RUN mix do local.hex --force, local.rebar --force
# set build ENV
ARG BUILD_MIX_ENV=prod
ENV MIX_ENV=${BUILD_MIX_ENV}
# install mix dependencies
COPY mix.exs mix.lock ./
RUN mix deps.get --only ${MIX_ENV}
RUN mkdir config
# copy compile-time config files before we compile dependencies
# to ensure any relevant config change will trigger the dependencies
# to be re-compiled.
COPY config/config.exs config/${BUILD_MIX_ENV}.exs config/
RUN mix deps.compile
COPY priv priv
COPY lib lib
# Compile the release
RUN mix compile
# Changes to config/runtime.exs don't require recompiling the code
COPY config/runtime.exs config/
COPY rel rel
RUN mix release
COPY ./mix.exs ./
EXPOSE 4000
ENTRYPOINT ["./priv/docker/service/docker-entrypoint.sh"]
CMD ["sample-cookie"]
# start a new build stage so that the final image will only contain
# the compiled release and other runtime necessities
FROM ${RUNNER_IMAGE}
RUN apt-get update -y \
&& apt-get install -y \
ca-certificates \
libncurses5 \
libstdc++6 \
locales \
openssl \
tini \
&& apt-get clean && rm -f /var/lib/apt/lists/*_*
# Set the locale
RUN sed -i '/en_US.UTF-8/s/^# //g' /etc/locale.gen && locale-gen
ENV LANG en_US.UTF-8
ENV LANGUAGE en_US:en
ENV LC_ALL en_US.UTF-8
WORKDIR /opt/app
RUN chown nobody /opt/app
# set runner ENV
ARG BUILD_MIX_ENV=prod
ENV MIX_ENV=${BUILD_MIX_ENV}
# Only copy the final release from the build stage
COPY --from=builder --chown=nobody:root /app/_build/${BUILD_MIX_ENV}/rel/wabanex ./
USER nobody
EXPOSE 4000
ENTRYPOINT ["tini", "--"]
CMD ["/app/bin/server"]

View File

@@ -1,6 +1,6 @@
.DEFAULT_GOAL := help .DEFAULT_GOAL := help
COMPOSE = docker compose -f docker-compose.yml -f docker-compose.override.yml COMPOSE = docker-compose -f docker-compose.yml -f docker-compose.override.yml
.PHONY: setup .PHONY: setup
setup: ## setup project setup: ## setup project
@@ -32,28 +32,9 @@ test: ## run tests
compose_up: ## start containers for this service compose_up: ## start containers for this service
@$(COMPOSE) up -d @$(COMPOSE) up -d
.PHONY: compose_watch .PHONY: compose_test
compose_watch: ## start containers for this service watching for updates in filesystem compose_test: ## run tests in containers
@$(COMPOSE) up -w @$(COMPOSE) run -e MIX_ENV=test --entrypoint make app test
.PHONY: compose_database_create
compose_database_create:
@$(COMPOSE) run --rm --entrypoint mix app ecto.create
.PHONY: compose_database_migrate
compose_database_migrate: ## apply migrations to our database
@$(COMPOSE) run --rm --entrypoint mix app ecto.migrate
.PHONY: compose_database_setup
compose_database_setup: compose_database_create compose_database_migrate ## create and apply migrations
.PHONY: compose_ps
compose_ps: ## status of containers
@$(COMPOSE) ps
.PHONY: compose_remote
compose_remote: ## connect to remote node
@$(COMPOSE) exec app ./priv/docker/service/docker-remote.sh
.PHONY: help .PHONY: help
help: help:

View File

@@ -1,3 +1,10 @@
# This file is responsible for configuring your application
# and its dependencies with the aid of the Mix.Config module.
#
# This configuration file is loaded before any dependency and
# is restricted to this project.
# General application configuration
import Config import Config
config :wabanex, config :wabanex,
@@ -7,13 +14,7 @@ config :wabanex, Wabanex.Repo,
migration_primary_key: [type: :binary_id], migration_primary_key: [type: :binary_id],
migration_foreign_key: [type: :binary_id] migration_foreign_key: [type: :binary_id]
config :wabanex, Wabanex.PromEx, # Configures the endpoint
disabled: false,
manual_metrics_start_delay: :no_delay,
drop_metrics_groups: [],
grafana: :disabled,
metrics_server: :disabled
config :wabanex, WabanexWeb.Endpoint, config :wabanex, WabanexWeb.Endpoint,
url: [host: "localhost"], url: [host: "localhost"],
secret_key_base: "wkyuhU+mCGwXUSBYVKZSRGoFmDYCbOFzdokbVmBBI9JgCWOqGPfuA/3JI5/b4Wdl", secret_key_base: "wkyuhU+mCGwXUSBYVKZSRGoFmDYCbOFzdokbVmBBI9JgCWOqGPfuA/3JI5/b4Wdl",
@@ -21,10 +22,14 @@ config :wabanex, WabanexWeb.Endpoint,
pubsub_server: Wabanex.PubSub, pubsub_server: Wabanex.PubSub,
live_view: [signing_salt: "SXtw7DzV"] live_view: [signing_salt: "SXtw7DzV"]
# Configures Elixir's Logger
config :logger, :console, config :logger, :console,
format: "$time $metadata[$level] $message\n", format: "$time $metadata[$level] $message\n",
metadata: [:request_id] metadata: [:request_id]
# Use Jason for JSON parsing in Phoenix
config :phoenix, :json_library, Jason config :phoenix, :json_library, Jason
# Import environment specific config. This must remain at the bottom
# of this file so it overrides the configuration defined above.
import_config "#{config_env()}.exs" import_config "#{config_env()}.exs"

View File

@@ -1,14 +1,17 @@
import Config import Config
config :wabanex, # Configure your database
dns_cluster_query: :ignore,
dns_cluster_resolver: Wabanex.DevDNSClusterResolver
config :wabanex, Wabanex.Repo, config :wabanex, Wabanex.Repo,
database: "wabanex_dev", database: "wabanex_dev",
show_sensitive_data_on_connection_error: true, show_sensitive_data_on_connection_error: true,
pool_size: 10 pool_size: 10
# For development, we disable any cache and enable
# debugging and code reloading.
#
# The watchers configuration can be used to run external
# watchers to your application. For example, we use it
# with webpack to recompile .js and .css sources.
config :wabanex, WabanexWeb.Endpoint, config :wabanex, WabanexWeb.Endpoint,
http: [port: 4000], http: [port: 4000],
debug_errors: true, debug_errors: true,
@@ -16,8 +19,36 @@ config :wabanex, WabanexWeb.Endpoint,
check_origin: false, check_origin: false,
watchers: [] watchers: []
# ## SSL Support
#
# In order to use HTTPS in development, a self-signed
# certificate can be generated by running the following
# Mix task:
#
# mix phx.gen.cert
#
# Note that this task requires Erlang/OTP 20 or later.
# Run `mix help phx.gen.cert` for more information.
#
# The `http:` config above can be replaced with:
#
# https: [
# port: 4001,
# cipher_suite: :strong,
# keyfile: "priv/cert/selfsigned_key.pem",
# certfile: "priv/cert/selfsigned.pem"
# ],
#
# If desired, both `http:` and `https:` keys can be
# configured to run both http and https servers on
# different ports.
# Do not include metadata nor timestamps in development logs
config :logger, :console, format: "[$level] $message\n" config :logger, :console, format: "[$level] $message\n"
# Set a higher stacktrace during development. Avoid configuring such
# in production as building large stacktraces may be expensive.
config :phoenix, :stacktrace_depth, 20 config :phoenix, :stacktrace_depth, 20
# Initialize plugs at runtime for faster development compilation
config :phoenix, :plug_init_mode, :runtime config :phoenix, :plug_init_mode, :runtime

View File

@@ -1,7 +1,55 @@
import Config import Config
# For production, don't forget to configure the url host
# to something meaningful, Phoenix uses this information
# when generating URLs.
#
# Note we also include the path to a cache manifest
# containing the digested version of static files. This
# manifest is generated by the `mix phx.digest` task,
# which you should run after static files are built and
# before starting your production server.
config :wabanex, WabanexWeb.Endpoint, config :wabanex, WabanexWeb.Endpoint,
url: [host: "example.com", port: 80], url: [host: "example.com", port: 80],
cache_static_manifest: "priv/static/cache_manifest.json" cache_static_manifest: "priv/static/cache_manifest.json"
# Do not print debug messages in production
config :logger, level: :info config :logger, level: :info
# ## SSL Support
#
# To get SSL working, you will need to add the `https` key
# to the previous section and set your `:url` port to 443:
#
# config :wabanex, WabanexWeb.Endpoint,
# ...
# url: [host: "example.com", port: 443],
# https: [
# port: 443,
# cipher_suite: :strong,
# keyfile: System.get_env("SOME_APP_SSL_KEY_PATH"),
# certfile: System.get_env("SOME_APP_SSL_CERT_PATH"),
# transport_options: [socket_opts: [:inet6]]
# ]
#
# The `cipher_suite` is set to `:strong` to support only the
# latest and more secure SSL ciphers. This means old browsers
# and clients may not be supported. You can set it to
# `:compatible` for wider support.
#
# `:keyfile` and `:certfile` expect an absolute path to the key
# and cert in disk or a relative path inside priv, for example
# "priv/ssl/server.key". For all supported SSL configuration
# options, see https://hexdocs.pm/plug/Plug.SSL.html#configure/1
#
# We also recommend setting `force_ssl` in your endpoint, ensuring
# no data is ever sent via http, always redirecting to https:
#
# config :wabanex, WabanexWeb.Endpoint,
# force_ssl: [hsts: true]
#
# Check `Plug.SSL` for all available options in `force_ssl`.
# Finally import the config/prod.secret.exs which loads secrets
# and configuration from environment variables.
import_config "prod.secret.exs"

View File

@@ -1,49 +1,6 @@
import Config import Config
# [warn] Conditional IPv6 support missing from runtime configuration.
#
# Add the following to your config/runtime.exs:
#
# maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []
#
# config :wabanex, Wabanex.Repo,
# ...,
# socket_options: maybe_ipv6
#
# [warn] Conditional server startup is missing from runtime configuration.
#
# Add the following to the top of your config/runtime.exs:
#
# if System.get_env("PHX_SERVER") do
# config :wabanex, WabanexWeb.Endpoint, server: true
# end
#
# [warn] Environment based URL export is missing from runtime configuration.
#
# Add the following to your config/runtime.exs:
#
# host = System.get_env("PHX_HOST") || "example.com"
#
# config :wabanex, WabanexWeb.Endpoint,
# ...,
# url: [host: host, port: 443]
config :wabanex, dns_cluster_query: System.get_env("DNS_CLUSTER_QUERY") || :ignore
multi_get_env = fn varnames, default ->
varnames
|> Enum.reduce(nil, fn
varname, nil ->
System.get_env(varname) || nil
_varname, value ->
value
end)
|> Kernel.||(default)
end
config :wabanex, Wabanex.Repo, config :wabanex, Wabanex.Repo,
username: multi_get_env.(["DB_USER", "POSTGRES_USER"], "postgres"), username: System.get_env("POSTGRES_USER") || "postgres",
password: multi_get_env.(["DB_PASSWORD", "POSTGRES_PASS"], "postgres"), password: System.get_env("POSTGRES_PASS") || "postgres",
hostname: multi_get_env.(["DB_HOST", "POSTGRES_HOST"], "localhost"), hostname: System.get_env("POSTGRES_HOST") || "localhost"
port: System.get_env("DB_PORT") || "5432"

View File

@@ -1,15 +1,22 @@
import Config import Config
# Configure your database
#
# The MIX_TEST_PARTITION environment variable can be used
# to provide built-in test partitioning in CI environment.
# Run `mix help test` for more information.
config :wabanex, Wabanex.Repo, config :wabanex, Wabanex.Repo,
database: "wabanex_test#{System.get_env("MIX_TEST_PARTITION")}", database: "wabanex_test#{System.get_env("MIX_TEST_PARTITION")}",
pool: Ecto.Adapters.SQL.Sandbox, pool: Ecto.Adapters.SQL.Sandbox
pool_size: System.schedulers_online() * 2
# We don't run a server during test. If one is required,
# you can enable the server option below.
config :wabanex, WabanexWeb.Endpoint, config :wabanex, WabanexWeb.Endpoint,
http: [port: 4002], http: [port: 4002],
server: false server: false
config :logger, level: :warning # Print only warnings and errors during test
config :logger, level: :warn
config :junit_formatter, config :junit_formatter,
report_file: "test_report.xml", report_file: "test_report.xml",

View File

@@ -1,58 +1,54 @@
--- ---
version: '3.7'
services: services:
db: db:
image: 'postgres:17.0-alpine' image: 'postgres:14.2-alpine'
hostname: &db_host db hostname: &db_host db
init: true init: true
environment: environment:
POSTGRES_USER: &db_user postgres POSTGRES_USER: &db_user postgres
POSTGRES_PASSWORD: &db_pass postgres POSTGRES_PASSWORD: &db_pass postgres
POSTGRES_DB: postgres POSTGRES_DB: &db_name postgres
volumes: volumes:
- './priv/docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql' - './priv/docker/postgres/init.sql:/docker-entrypoint-initdb.d/init.sql'
- 'db_data:/var/lib/postgresql/data' - 'db_data:/var/lib/postgresql/data'
restart: unless-stopped restart: unless-stopped
app: app:
image: 'joaodubas/ex_trainer:${EX_TRAINER_TAG:-dev}' image: 'elixir:1.13.4'
build: hostname: app
target: builder
context: .
args:
BUILD_MIX_ENV: dev
hostname: &app_host ex_trainer
depends_on: depends_on:
- db - db
init: true init: true
develop:
watch:
- path: ./
ignore:
- ./build/
- ./deps/
target: /opt/app
action: sync
- path: ./config/
target: /opt/app
action: sync+restart
- path: ./lib/wabanex/application.ex
target: /opt/app
action: sync+restart
- path: ./mix.exs
target: /opt/app
action: sync+restart
- path: ./mix.lock
action: rebuild
environment: environment:
DNS_CLUSTER_QUERY: *app_host
POSTGRES_HOST: *db_host POSTGRES_HOST: *db_host
POSTGRES_USER: *db_user POSTGRES_USER: *db_user
POSTGRES_PASS: *db_pass POSTGRES_PASS: *db_pass
POSTGRES_NAME: wabanex_dev POSTGRES_NAME: wabanex_dev
volumes:
- '.:/opt/app'
- 'app_build:/opt/app/_build'
- 'app_deps:/opt/app/deps'
working_dir: /opt/app working_dir: /opt/app
entrypoint: sleep
command: infinity
pgcli:
image: 'joaodubas/pgcli:latest'
hostname: development
depends_on:
- db
environment:
PGUSER: *db_user
PGPASSWORD: *db_pass
PGHOST: *db_host
PGDATABASE: wabanex_dev
volumes:
- './priv/docker/pgcli:/root/.config/pgcli'
restart: unless-stopped restart: unless-stopped
scale: 3 entrypoint: sleep
entrypoint: ./priv/docker/service/docker-entrypoint.sh command: 3650d
command: local-cookie
volumes: volumes:
db_data: {} db_data: {}
app_build: {}
app_deps: {}

View File

@@ -1,25 +1,32 @@
defmodule Wabanex.Application do defmodule Wabanex.Application do
# See https://hexdocs.pm/elixir/Application.html
# for more information on OTP Applications
@moduledoc false @moduledoc false
use Application use Application
def start(_type, _args) do def start(_type, _args) do
children = [ children = [
Wabanex.PromEx, # Start the Ecto repository
Wabanex.Repo, Wabanex.Repo,
# Start the Telemetry supervisor
WabanexWeb.Telemetry, WabanexWeb.Telemetry,
# Start the PubSub system
{Phoenix.PubSub, name: Wabanex.PubSub}, {Phoenix.PubSub, name: Wabanex.PubSub},
{DNSCluster, # Start the Endpoint (http/https)
query: Application.get_env(:wabanex, :dns_cluster_query) || :ignore,
log: :info,
resolver: Application.get_env(:wabanex, :dns_cluster_resolver) || DNSCluster.Resolver},
WabanexWeb.Endpoint WabanexWeb.Endpoint
# Start a worker by calling: Wabanex.Worker.start_link(arg)
# {Wabanex.Worker, arg}
] ]
# See https://hexdocs.pm/elixir/Supervisor.html
# for other strategies and supported options
opts = [strategy: :one_for_one, name: Wabanex.Supervisor] opts = [strategy: :one_for_one, name: Wabanex.Supervisor]
Supervisor.start_link(children, opts) Supervisor.start_link(children, opts)
end end
# Tell Phoenix to update the endpoint configuration
# whenever the application is updated.
def config_change(changed, _new, removed) do def config_change(changed, _new, removed) do
WabanexWeb.Endpoint.config_change(changed, removed) WabanexWeb.Endpoint.config_change(changed, removed)
:ok :ok

View File

@@ -1,26 +0,0 @@
defmodule Wabanex.DevDNSClusterResolver do
@moduledoc """
Local DNS resolver for cluster query.
"""
require Record
Record.defrecord(:hostent, Record.extract(:hostent, from_lib: "kernel/include/inet.hrl"))
def basename(node_name) when is_atom(node_name) do
[basename, _] = node_name |> to_string() |> String.split("@")
basename
end
def connect_node(node_name) when is_atom(node_name) do
Node.connect(node_name)
end
def list_nodes, do: Node.list(:visible)
def lookup(query, type) when is_binary(query) and type in [:a, :aaaa] do
case :inet_res.getbyname(~c"#{query}", type) do
{:ok, hostent(h_addr_list: addr_list)} -> addr_list
{:error, _} -> []
end
end
end

View File

@@ -1,102 +0,0 @@
defmodule Wabanex.PromEx do
@moduledoc """
Be sure to add the following to finish setting up PromEx:
1. Update your configuration (config.exs, dev.exs, prod.exs, releases.exs, etc) to
configure the necessary bit of PromEx. Be sure to check out `PromEx.Config` for
more details regarding configuring PromEx:
```
config :wabanex, Wabanex.PromEx,
disabled: false,
manual_metrics_start_delay: :no_delay,
drop_metrics_groups: [],
grafana: :disabled,
metrics_server: :disabled
```
2. Add this module to your application supervision tree. It should be one of the first
things that is started so that no Telemetry events are missed. For example, if PromEx
is started after your Repo module, you will miss Ecto's init events and the dashboards
will be missing some data points:
```
def start(_type, _args) do
children = [
Wabanex.PromEx,
...
]
...
end
```
3. Update your `endpoint.ex` file to expose your metrics (or configure a standalone
server using the `:metrics_server` config options). Be sure to put this plug before
your `Plug.Telemetry` entry so that you can avoid having calls to your `/metrics`
endpoint create their own metrics and logs which can pollute your logs/metrics given
that Prometheus will scrape at a regular interval and that can get noisy:
```
defmodule WabanexWeb.Endpoint do
use Phoenix.Endpoint, otp_app: :wabanex
...
plug PromEx.Plug, prom_ex_module: Wabanex.PromEx
...
end
```
4. Update the list of plugins in the `plugins/0` function return list to reflect your
application's dependencies. Also update the list of dashboards that are to be uploaded
to Grafana in the `dashboards/0` function.
"""
use PromEx, otp_app: :wabanex
alias PromEx.Plugins
@impl true
def plugins do
[
# PromEx built in plugins
Plugins.Application,
Plugins.Beam,
# {Plugins.Phoenix, router: WabanexWeb.Router, endpoint: WabanexWeb.Endpoint},
Plugins.Ecto,
# Plugins.Oban,
# Plugins.PhoenixLiveView,
Plugins.Absinthe
# Plugins.Broadway,
# Add your own PromEx metrics plugins
# Wabanex.Users.PromExPlugin
]
end
@impl true
def dashboard_assigns do
[
datasource_id: "prometheus",
default_selected_interval: "30s"
]
end
@impl true
def dashboards do
[
# PromEx built in Grafana dashboards
{:prom_ex, "application.json"},
{:prom_ex, "beam.json"},
# {:prom_ex, "phoenix.json"},
{:prom_ex, "ecto.json"},
# {:prom_ex, "oban.json"},
# {:prom_ex, "phoenix_live_view.json"},
{:prom_ex, "absinthe.json"}
# {:prom_ex, "broadway.json"},
# Add your dashboard definitions here with the format: {:otp_app, "path_in_priv"}
# {:wabanex, "/grafana_dashboards/user_metrics.json"}
]
end
end

View File

@@ -1,28 +0,0 @@
defmodule Wabanex.Release do
@moduledoc """
Used for executing DB release tasks when run in production without Mix
installed.
"""
@app :wabanex
def migrate do
load_app()
for repo <- repos() do
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :up, all: true))
end
end
def rollback(repo, version) do
load_app()
{:ok, _, _} = Ecto.Migrator.with_repo(repo, &Ecto.Migrator.run(&1, :down, to: version))
end
defp repos do
Application.fetch_env!(@app, :ecto_repos)
end
defp load_app do
Application.load(@app)
end
end

View File

@@ -19,10 +19,10 @@ defmodule WabanexWeb do
def controller do def controller do
quote do quote do
use Gettext, backend: WabanexWeb.Gettext
use Phoenix.Controller, namespace: WabanexWeb use Phoenix.Controller, namespace: WabanexWeb
import Plug.Conn import Plug.Conn
import WabanexWeb.Gettext
alias WabanexWeb.Router.Helpers, as: Routes alias WabanexWeb.Router.Helpers, as: Routes
end end
end end
@@ -54,18 +54,17 @@ defmodule WabanexWeb do
def channel do def channel do
quote do quote do
use Phoenix.Channel use Phoenix.Channel
use Gettext, backend: WabanexWeb.Gettext import WabanexWeb.Gettext
end end
end end
defp view_helpers do defp view_helpers do
quote do quote do
use Gettext, backend: WabanexWeb.Gettext
# Import basic rendering functionality (render, render_layout, etc) # Import basic rendering functionality (render, render_layout, etc)
import Phoenix.View import Phoenix.View
import WabanexWeb.ErrorHelpers import WabanexWeb.ErrorHelpers
import WabanexWeb.Gettext
alias WabanexWeb.Router.Helpers, as: Routes alias WabanexWeb.Router.Helpers, as: Routes
end end
end end

View File

@@ -16,8 +16,6 @@ defmodule WabanexWeb.Endpoint do
socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]] socket "/live", Phoenix.LiveView.Socket, websocket: [connect_info: [session: @session_options]]
plug PromEx.Plug, prom_ex_module: Wabanex.PromEx
# Serve at "/" the static files from "priv/static" directory. # Serve at "/" the static files from "priv/static" directory.
# #
# You should set gzip to true if you are running phx.digest # You should set gzip to true if you are running phx.digest

View File

@@ -5,7 +5,7 @@ defmodule WabanexWeb.Gettext do
By using [Gettext](https://hexdocs.pm/gettext), By using [Gettext](https://hexdocs.pm/gettext),
your module gains a set of macros for translations, for example: your module gains a set of macros for translations, for example:
use Gettext, backend: WabanexWeb.Gettext import WabanexWeb.Gettext
# Simple translation # Simple translation
gettext("Here is the string to translate") gettext("Here is the string to translate")
@@ -20,5 +20,5 @@ defmodule WabanexWeb.Gettext do
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage. See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
""" """
use Gettext.Backend, otp_app: :wabanex use Gettext, otp_app: :wabanex
end end

View File

@@ -17,11 +17,10 @@ defmodule WabanexWeb.Schema.Types.Custom.DateRange do
end end
@spec serialize_range(PgRanges.DateRange.t()) :: String.t() @spec serialize_range(PgRanges.DateRange.t()) :: String.t()
@spec serialize_range(list(DateTime.t() | nil | atom)) :: String.t() @spec serialize_range(list(DateTime.t() | nil)) :: String.t()
defp serialize_range(%PgRanges.DateRange{lower: start_range, upper: end_range}), defp serialize_range(%PgRanges.DateRange{lower: start_range, upper: end_range}),
do: serialize_range([start_range, end_range]) do: serialize_range([start_range, end_range])
defp serialize_range([start_range, :unbound]), do: serialize_range([start_range, nil])
defp serialize_range([start_range, nil]), do: "#{Date.to_iso8601(start_range)}," defp serialize_range([start_range, nil]), do: "#{Date.to_iso8601(start_range)},"
defp serialize_range([start_range, end_range]), defp serialize_range([start_range, end_range]),

44
mix.exs
View File

@@ -7,7 +7,7 @@ defmodule Wabanex.MixProject do
version: "0.1.0", version: "0.1.0",
elixir: "~> 1.7", elixir: "~> 1.7",
elixirc_paths: elixirc_paths(Mix.env()), elixirc_paths: elixirc_paths(Mix.env()),
compilers: Mix.compilers(), compilers: [:phoenix, :gettext] ++ Mix.compilers(),
start_permanent: Mix.env() == :prod, start_permanent: Mix.env() == :prod,
dialyzer: [plt_core_path: "priv/plts"], dialyzer: [plt_core_path: "priv/plts"],
test_coverage: [tool: LcovEx, output: "cover"], test_coverage: [tool: LcovEx, output: "cover"],
@@ -29,32 +29,24 @@ defmodule Wabanex.MixProject do
defp deps do defp deps do
[ [
{:absinthe, "~> 1.7.0"}, {:absinthe, "~> 1.5"},
{:absinthe_plug, {:absinthe_plug, "~> 1.5"},
git: "https://github.com/absinthe-graphql/absinthe_plug.git", {:credo, "~> 1.5", only: [:dev, :test], runtime: false},
ref: "3a984cc341ebb32c79e7ae58b4ebd116d5c62f9e"},
{:credo, "~> 1.7.0", only: [:dev, :test], runtime: false},
{:crudry, "~> 2.4.0"}, {:crudry, "~> 2.4.0"},
{:dialyxir, "~> 1.4.0", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.1", only: [:dev, :test], runtime: false},
{:dns_cluster, "~> 0.1.1"}, {:ecto_sql, "~> 3.4"},
{:ecto_sql, "~> 3.12.0"}, {:gettext, "~> 0.19"},
{:gettext, "~> 0.26.0"}, {:jason, "~> 1.0"},
{:jason, "~> 1.4.0"}, {:junit_formatter, "~> 3.1", only: [:test]},
{:junit_formatter, "~> 3.4.0", only: [:test]}, {:lcov_ex, "~> 0.2", only: [:dev, :test], runtime: false},
{:lcov_ex, "~> 0.3.0", only: [:dev, :test], runtime: false}, {:pg_ranges, "~> 1.1"},
{:mix_audit, "~> 2.1.0", only: [:dev, :test], runtime: false}, {:phoenix, "~> 1.6.0"},
{:pg_ranges, "~> 1.1.0"}, {:phoenix_ecto, "~> 4.1"},
{:phoenix, "~> 1.7.0"}, {:phoenix_live_dashboard, "~> 0.6"},
{:phoenix_ecto, "~> 4.6.0"}, {:plug_cowboy, "~> 2.0"},
{:phoenix_view, "~> 2.0.0"}, {:postgrex, ">= 0.0.0"},
{:phoenix_live_dashboard, "~> 0.8.0"}, {:telemetry_metrics, "~> 0.6"},
{:plug_cowboy, "~> 2.7.0"}, {:telemetry_poller, "~> 1.0"}
{:postgrex, "~> 0.19.0"},
{:prom_ex, "~> 1.10.0"},
{:sobelow, "~> 0.13", only: [:dev, :test], runtime: false},
{:telemetry_metrics, "~> 1.0.0"},
{:telemetry_poller, "~> 1.1.0"},
{:testcontainers, "~> 1.10.0", only: [:dev, :test]}
] ]
end end

107
mix.lock
View File

@@ -1,71 +1,46 @@
%{ %{
"absinthe": {:hex, :absinthe, "1.7.8", "43443d12ad2b4fcce60e257ac71caf3081f3d5c4ddd5eac63a02628bcaf5b556", [:mix], [{:dataloader, "~> 1.0.0 or ~> 2.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 1.2.2 or ~> 1.3", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:opentelemetry_process_propagator, "~> 0.2.1 or ~> 0.3", [hex: :opentelemetry_process_propagator, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "c4085df201892a498384f997649aedb37a4ce8a726c170d5b5617ed3bf45d40b"}, "absinthe": {:hex, :absinthe, "1.7.0", "36819e7b1fd5046c9c734f27fe7e564aed3bda59f0354c37cd2df88fd32dd014", [:mix], [{:dataloader, "~> 1.0.0", [hex: :dataloader, repo: "hexpm", optional: true]}, {:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}, {:nimble_parsec, "~> 0.5 or ~> 1.0", [hex: :nimble_parsec, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0 or ~> 0.4", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "566a5b5519afc9b29c4d367f0c6768162de3ec03e9bf9916f9dc2bcbe7c09643"},
"absinthe_plug": {:git, "https://github.com/absinthe-graphql/absinthe_plug.git", "3a984cc341ebb32c79e7ae58b4ebd116d5c62f9e", [ref: "3a984cc341ebb32c79e7ae58b4ebd116d5c62f9e"]}, "absinthe_plug": {:hex, :absinthe_plug, "1.5.8", "38d230641ba9dca8f72f1fed2dfc8abd53b3907d1996363da32434ab6ee5d6ab", [:mix], [{:absinthe, "~> 1.5", [hex: :absinthe, repo: "hexpm", optional: false]}, {:plug, "~> 1.4", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "bbb04176647b735828861e7b2705465e53e2cf54ccf5a73ddd1ebd855f996e5a"},
"bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, "bunt": {:hex, :bunt, "0.2.0", "951c6e801e8b1d2cbe58ebbd3e616a869061ddadcc4863d0a2182541acae9a38", [:mix], [], "hexpm", "7af5c7e09fe1d40f76c8e4f9dd2be7cebd83909f31fee7cd0e9eadc567da8353"},
"castore": {:hex, :castore, "1.0.8", "dedcf20ea746694647f883590b82d9e96014057aff1d44d03ec90f36a5c0dc6e", [:mix], [], "hexpm", "0b2b66d2ee742cb1d9cb8c8be3b43c3a70ee8651f37b75a8b982e036752983f1"}, "castore": {:hex, :castore, "0.1.16", "2675f717adc700475345c5512c381ef9273eb5df26bdd3f8c13e2636cf4cc175", [:mix], [], "hexpm", "28ed2c43d83b5c25d35c51bc0abf229ac51359c170cba76171a462ced2e4b651"},
"certifi": {:hex, :certifi, "2.12.0", "2d1cca2ec95f59643862af91f001478c9863c2ac9cb6e2f89780bfd8de987329", [:rebar3], [], "hexpm", "ee68d85df22e554040cdb4be100f33873ac6051387baf6a8f6ce82272340ff1c"}, "connection": {:hex, :connection, "1.1.0", "ff2a49c4b75b6fb3e674bfc5536451607270aac754ffd1bdfe175abe4a6d7a68", [:mix], [], "hexpm", "722c1eb0a418fbe91ba7bd59a47e28008a189d47e37e0e7bb85585a016b2869c"},
"cowboy": {:hex, :cowboy, "2.12.0", "f276d521a1ff88b2b9b4c54d0e753da6c66dd7be6c9fca3d9418b561828a3731", [:make, :rebar3], [{:cowlib, "2.13.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "8a7abe6d183372ceb21caa2709bec928ab2b72e18a3911aa1771639bef82651e"}, "cowboy": {:hex, :cowboy, "2.9.0", "865dd8b6607e14cf03282e10e934023a1bd8be6f6bacf921a7e2a96d800cd452", [:make, :rebar3], [{:cowlib, "2.11.0", [hex: :cowlib, repo: "hexpm", optional: false]}, {:ranch, "1.8.0", [hex: :ranch, repo: "hexpm", optional: false]}], "hexpm", "2c729f934b4e1aa149aff882f57c6372c15399a20d54f65c8d67bef583021bde"},
"cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"}, "cowboy_telemetry": {:hex, :cowboy_telemetry, "0.4.0", "f239f68b588efa7707abce16a84d0d2acf3a0f50571f8bb7f56a15865aae820c", [:rebar3], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7d98bac1ee4565d31b62d59f8823dfd8356a169e7fcbb83831b8a5397404c9de"},
"cowlib": {:hex, :cowlib, "2.13.0", "db8f7505d8332d98ef50a3ef34b34c1afddec7506e4ee4dd4a3a266285d282ca", [:make, :rebar3], [], "hexpm", "e1e1284dc3fc030a64b1ad0d8382ae7e99da46c3246b815318a4b848873800a4"}, "cowlib": {:hex, :cowlib, "2.11.0", "0b9ff9c346629256c42ebe1eeb769a83c6cb771a6ee5960bd110ab0b9b872063", [:make, :rebar3], [], "hexpm", "2b3e9da0b21c4565751a6d4901c20d1b4cc25cbb7fd50d91d2ab6dd287bc86a9"},
"credo": {:hex, :credo, "1.7.8", "9722ba1681e973025908d542ec3d95db5f9c549251ba5b028e251ad8c24ab8c5", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cb9e87cc64f152f3ed1c6e325e7b894dea8f5ef2e41123bd864e3cd5ceb44968"}, "credo": {:hex, :credo, "1.6.4", "ddd474afb6e8c240313f3a7b0d025cc3213f0d171879429bf8535d7021d9ad78", [:mix], [{:bunt, "~> 0.2.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2.8", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "c28f910b61e1ff829bffa056ef7293a8db50e87f2c57a9b5c3f57eee124536b7"},
"crudry": {:hex, :crudry, "2.4.0", "d175f1a8ee44456e852ae6b4d75997642a3e2a9f62ac28e4736656856c80dff5", [:mix], [{:absinthe, ">= 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:gettext, ">= 0.0.0", [hex: :gettext, repo: "hexpm", optional: false]}], "hexpm", "a14150b3f82e060e602d67f2c52c6195f0fefb49aee7d226d68dc3b83b8f58dc"}, "crudry": {:hex, :crudry, "2.4.0", "d175f1a8ee44456e852ae6b4d75997642a3e2a9f62ac28e4736656856c80dff5", [:mix], [{:absinthe, ">= 1.4.0", [hex: :absinthe, repo: "hexpm", optional: false]}, {:ecto, ">= 3.0.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:gettext, ">= 0.0.0", [hex: :gettext, repo: "hexpm", optional: false]}], "hexpm", "a14150b3f82e060e602d67f2c52c6195f0fefb49aee7d226d68dc3b83b8f58dc"},
"db_connection": {:hex, :db_connection, "2.7.0", "b99faa9291bb09892c7da373bb82cba59aefa9b36300f6145c5f201c7adf48ec", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dcf08f31b2701f857dfc787fbad78223d61a32204f217f15e881dd93e4bdd3ff"}, "db_connection": {:hex, :db_connection, "2.4.2", "f92e79aff2375299a16bcb069a14ee8615c3414863a6fef93156aee8e86c2ff3", [:mix], [{:connection, "~> 1.0", [hex: :connection, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "4fe53ca91b99f55ea249693a0229356a08f4d1a7931d8ffa79289b145fe83668"},
"decimal": {:hex, :decimal, "2.1.1", "5611dca5d4b2c3dd497dec8f68751f1f1a54755e8ed2a966c2633cf885973ad6", [:mix], [], "hexpm", "53cfe5f497ed0e7771ae1a475575603d77425099ba5faef9394932b35020ffcc"}, "decimal": {:hex, :decimal, "1.9.0", "83e8daf59631d632b171faabafb4a9f4242c514b0a06ba3df493951c08f64d07", [:mix], [], "hexpm", "b1f2343568eed6928f3e751cf2dffde95bfaa19dd95d09e8a9ea92ccfd6f7d85"},
"dialyxir": {:hex, :dialyxir, "1.4.4", "fb3ce8741edeaea59c9ae84d5cec75da00fa89fe401c72d6e047d11a61f65f70", [:mix], [{:erlex, ">= 0.2.7", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "cd6111e8017ccd563e65621a4d9a4a1c5cd333df30cebc7face8029cacb4eff6"}, "dialyxir": {:hex, :dialyxir, "1.1.0", "c5aab0d6e71e5522e77beff7ba9e08f8e02bad90dfbeffae60eaf0cb47e29488", [:mix], [{:erlex, ">= 0.2.6", [hex: :erlex, repo: "hexpm", optional: false]}], "hexpm", "07ea8e49c45f15264ebe6d5b93799d4dd56a44036cf42d0ad9c960bc266c0b9a"},
"dns_cluster": {:hex, :dns_cluster, "0.1.3", "0bc20a2c88ed6cc494f2964075c359f8c2d00e1bf25518a6a6c7fd277c9b0c66", [:mix], [], "hexpm", "46cb7c4a1b3e52c7ad4cbe33ca5079fbde4840dedeafca2baf77996c2da1bc33"}, "ecto": {:hex, :ecto, "3.7.2", "44c034f88e1980754983cc4400585970b4206841f6f3780967a65a9150ef09a8", [:mix], [{:decimal, "~> 1.6 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a600da5772d1c31abbf06f3e4a1ffb150e74ed3e2aa92ff3cee95901657a874e"},
"ecto": {:hex, :ecto, "3.12.0", "9014a3ccac7f91e680b9d237d461ebe3d4e16d62ca8e355d540e2c6afdc28309", [:mix], [{:decimal, "~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "41e781a76e131093af8e1edf68b1319bf320878faff58da41ffa4b10fc6ff678"}, "ecto_sql": {:hex, :ecto_sql, "3.7.2", "55c60aa3a06168912abf145c6df38b0295c34118c3624cf7a6977cd6ce043081", [:mix], [{:db_connection, "~> 2.2", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.7.0", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.4.0 or ~> 0.5.0 or ~> 0.6.0", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.15.0 or ~> 0.16.0 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "3c218ea62f305dcaef0b915fb56583195e7b91c91dcfb006ba1f669bfacbff2a"},
"ecto_sql": {:hex, :ecto_sql, "3.12.0", "73cea17edfa54bde76ee8561b30d29ea08f630959685006d9c6e7d1e59113b7d", [:mix], [{:db_connection, "~> 2.4.1 or ~> 2.5", [hex: :db_connection, repo: "hexpm", optional: false]}, {:ecto, "~> 3.12", [hex: :ecto, repo: "hexpm", optional: false]}, {:myxql, "~> 0.7", [hex: :myxql, repo: "hexpm", optional: true]}, {:postgrex, "~> 0.19 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}, {:tds, "~> 2.1.1 or ~> 2.2", [hex: :tds, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4.0 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dc9e4d206f274f3947e96142a8fdc5f69a2a6a9abb4649ef5c882323b6d512f0"}, "erlex": {:hex, :erlex, "0.2.6", "c7987d15e899c7a2f34f5420d2a2ea0d659682c06ac607572df55a43753aa12e", [:mix], [], "hexpm", "2ed2e25711feb44d52b17d2780eabf998452f6efda104877a3881c2f8c0c0c75"},
"elixir_uuid": {:hex, :elixir_uuid, "1.2.1", "dce506597acb7e6b0daeaff52ff6a9043f5919a4c3315abb4143f0b00378c097", [:mix], [], "hexpm", "f7eba2ea6c3555cea09706492716b0d87397b88946e6380898c2889d68585752"}, "file_system": {:hex, :file_system, "0.2.10", "fb082005a9cd1711c05b5248710f8826b02d7d1784e7c3451f9c1231d4fc162d", [:mix], [], "hexpm", "41195edbfb562a593726eda3b3e8b103a309b733ad25f3d642ba49696bf715dc"},
"erlex": {:hex, :erlex, "0.2.7", "810e8725f96ab74d17aac676e748627a07bc87eb950d2b83acd29dc047a30595", [:mix], [], "hexpm", "3ed95f79d1a844c3f6bf0cea61e0d5612a42ce56da9c03f01df538685365efb0"}, "finch": {:hex, :finch, "0.10.2", "9ad27d68270d879f73f26604bb2e573d40f29bf0e907064a9a337f90a16a0312", [:mix], [{:castore, "~> 0.1", [hex: :castore, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "dd8b11b282072cec2ef30852283949c248bd5d2820c88d8acc89402b81db7550"},
"ex_docker_engine_api": {:hex, :ex_docker_engine_api, "1.43.2", "011c7ace8f9db0d03664c0ad763886831462cb0244cd024ab9326463ec3ff283", [:mix], [{:hackney, "~> 1.20", [hex: :hackney, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:tesla, "~> 1.7", [hex: :tesla, repo: "hexpm", optional: false]}], "hexpm", "f3884963ad742ee02cbf3277a75371569292ceee81df7f679a3021a3b64bf1ab"}, "gettext": {:hex, :gettext, "0.19.1", "564953fd21f29358e68b91634799d9d26989f8d039d7512622efb3c3b1c97892", [:mix], [], "hexpm", "10c656c0912b8299adba9b061c06947511e3f109ab0d18b44a866a4498e77222"},
"expo": {:hex, :expo, "1.1.0", "f7b9ed7fb5745ebe1eeedf3d6f29226c5dd52897ac67c0f8af62a07e661e5c75", [:mix], [], "hexpm", "fbadf93f4700fb44c331362177bdca9eeb8097e8b0ef525c9cc501cb9917c960"}, "hpax": {:hex, :hpax, "0.1.1", "2396c313683ada39e98c20a75a82911592b47e5c24391363343bde74f82396ca", [:mix], [], "hexpm", "0ae7d5a0b04a8a60caf7a39fcf3ec476f35cc2cc16c05abea730d3ce6ac6c826"},
"file_system": {:hex, :file_system, "1.0.0", "b689cc7dcee665f774de94b5a832e578bd7963c8e637ef940cd44327db7de2cd", [:mix], [], "hexpm", "6752092d66aec5a10e662aefeed8ddb9531d79db0bc145bb8c40325ca1d8536d"}, "jason": {:hex, :jason, "1.3.0", "fa6b82a934feb176263ad2df0dbd91bf633d4a46ebfdffea0c8ae82953714946", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "53fc1f51255390e0ec7e50f9cb41e751c260d065dcba2bf0d08dc51a4002c2ac"},
"finch": {:hex, :finch, "0.18.0", "944ac7d34d0bd2ac8998f79f7a811b21d87d911e77a786bc5810adb75632ada4", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.3", [hex: :mint, repo: "hexpm", optional: false]}, {:nimble_options, "~> 0.4 or ~> 1.0", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:nimble_pool, "~> 0.2.6 or ~> 1.0", [hex: :nimble_pool, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "69f5045b042e531e53edc2574f15e25e735b522c37e2ddb766e15b979e03aa65"}, "junit_formatter": {:hex, :junit_formatter, "3.3.1", "c729befb848f1b9571f317d2fefa648e9d4869befc4b2980daca7c1edc468e40", [:mix], [], "hexpm", "761fc5be4b4c15d8ba91a6dafde0b2c2ae6db9da7b8832a55b5a1deb524da72b"},
"fs": {:hex, :fs, "8.6.1", "7c9c0d0211e8c520e4e9eda63b960605c2711839f47285e6166c332d973be8ea", [:rebar3], [], "hexpm", "61ea2bdaedae4e2024d0d25c63e44dccf65622d4402db4a2df12868d1546503f"}, "lcov_ex": {:hex, :lcov_ex, "0.2.0", "4ae06fc23e7dc7f06cddabf44b97901bb4a79cd7b783bce411d07131d6d5edd2", [:mix], [], "hexpm", "c5e33def56f9ae9de40171012c1c47fcbd4abaae430193aad4d4062a8d336970"},
"gettext": {:hex, :gettext, "0.26.1", "38e14ea5dcf962d1fc9f361b63ea07c0ce715a8ef1f9e82d3dfb8e67e0416715", [:mix], [{:expo, "~> 0.5.1 or ~> 1.0", [hex: :expo, repo: "hexpm", optional: false]}], "hexpm", "01ce56f188b9dc28780a52783d6529ad2bc7124f9744e571e1ee4ea88bf08734"}, "mime": {:hex, :mime, "2.0.2", "0b9e1a4c840eafb68d820b0e2158ef5c49385d17fb36855ac6e7e087d4b1dcc5", [:mix], [], "hexpm", "e6a3f76b4c277739e36c2e21a2c640778ba4c3846189d5ab19f97f126df5f9b7"},
"hackney": {:hex, :hackney, "1.20.1", "8d97aec62ddddd757d128bfd1df6c5861093419f8f7a4223823537bad5d064e2", [:rebar3], [{:certifi, "~> 2.12.0", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "~> 6.1.0", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "~> 1.0.0", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "~> 1.1", [hex: :mimerl, repo: "hexpm", optional: false]}, {:parse_trans, "3.4.1", [hex: :parse_trans, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1.0", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}, {:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "fe9094e5f1a2a2c0a7d10918fee36bfec0ec2a979994cff8cfe8058cd9af38e3"}, "mint": {:hex, :mint, "1.4.1", "49b3b6ea35a9a38836d2ad745251b01ca9ec062f7cb66f546bf22e6699137126", [:mix], [{:castore, "~> 0.1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "cd261766e61011a9079cccf8fa9d826e7a397c24fbedf0e11b49312bea629b58"},
"hpax": {:hex, :hpax, "1.0.0", "28dcf54509fe2152a3d040e4e3df5b265dcb6cb532029ecbacf4ce52caea3fd2", [:mix], [], "hexpm", "7f1314731d711e2ca5fdc7fd361296593fc2542570b3105595bb0bc6d0fad601"}, "nimble_options": {:hex, :nimble_options, "0.4.0", "c89babbab52221a24b8d1ff9e7d838be70f0d871be823165c94dd3418eea728f", [:mix], [], "hexpm", "e6701c1af326a11eea9634a3b1c62b475339ace9456c1a23ec3bc9a847bca02d"},
"idna": {:hex, :idna, "6.1.1", "8a63070e9f7d0c62eb9d9fcb360a7de382448200fbbd1b106cc96d3d8099df8d", [:rebar3], [{:unicode_util_compat, "~> 0.7.0", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm", "92376eb7894412ed19ac475e4a86f7b413c1b9fbb5bd16dccd57934157944cea"}, "nimble_parsec": {:hex, :nimble_parsec, "1.2.3", "244836e6e3f1200c7f30cb56733fd808744eca61fd182f731eac4af635cc6d0b", [:mix], [], "hexpm", "c8d789e39b9131acf7b99291e93dae60ab48ef14a7ee9d58c6964f59efb570b0"},
"jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, "nimble_pool": {:hex, :nimble_pool, "0.2.6", "91f2f4c357da4c4a0a548286c84a3a28004f68f05609b4534526871a22053cde", [:mix], [], "hexpm", "1c715055095d3f2705c4e236c18b618420a35490da94149ff8b580a2144f653f"},
"junit_formatter": {:hex, :junit_formatter, "3.4.0", "d0e8db6c34dab6d3c4154c3b46b21540db1109ae709d6cf99ba7e7a2ce4b1ac2", [:mix], [], "hexpm", "bb36e2ae83f1ced6ab931c4ce51dd3dbef1ef61bb4932412e173b0cfa259dacd"}, "pg_ranges": {:hex, :pg_ranges, "1.1.0", "cfac1ee59958213cd6b066cc8bb5d63f6af7f830fa05fc633f33ee5da7876c94", [:mix], [{:decimal, "~> 1.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto_sql, ">= 3.3.0", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "2750f923666f548572e73b1636066196d7bd47ea2c63a1ad2c31692d16fd8590"},
"lcov_ex": {:hex, :lcov_ex, "0.3.3", "1745a88e46606c4f86408299f54878b7d0cd22ea3e9c54b0018b6ed631a9ce87", [:mix], [], "hexpm", "ea373ec4d2df213357c5a464be16ab08d1e58e61ea2de784a483780c22a1e74a"}, "phoenix": {:hex, :phoenix, "1.6.7", "f1de32418bbbcd471f4fe74d3860ee9c8e8c6c36a0ec173be8ff468a5d72ac90", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.0", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 1.0", [hex: :phoenix_view, repo: "hexpm", optional: false]}, {:plug, "~> 1.10", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.2", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b354a4f11d9a2f3a380fb731042dae064f22d7aed8c7e7c024a2459f12994aad"},
"metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm", "69b09adddc4f74a40716ae54d140f93beb0fb8978d8636eaded0c31b6f099f16"}, "phoenix_ecto": {:hex, :phoenix_ecto, "4.4.0", "0672ed4e4808b3fbed494dded89958e22fb882de47a97634c0b13e7b0b5f7720", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "09864e558ed31ee00bd48fcc1d4fc58ae9678c9e81649075431e69dbabb43cc1"},
"mime": {:hex, :mime, "2.0.6", "8f18486773d9b15f95f4f4f1e39b710045fa1de891fada4516559967276e4dc2", [:mix], [], "hexpm", "c9945363a6b26d747389aac3643f8e0e09d30499a138ad64fe8fd1d13d9b153e"}, "phoenix_html": {:hex, :phoenix_html, "3.2.0", "1c1219d4b6cb22ac72f12f73dc5fad6c7563104d083f711c3fcd8551a1f4ae11", [:mix], [{:plug, "~> 1.5", [hex: :plug, repo: "hexpm", optional: true]}], "hexpm", "36ec97ba56d25c0136ef1992c37957e4246b649d620958a1f9fa86165f8bc54f"},
"mimerl": {:hex, :mimerl, "1.3.0", "d0cd9fc04b9061f82490f6581e0128379830e78535e017f7780f37fea7545726", [:rebar3], [], "hexpm", "a1e15a50d1887217de95f0b9b0793e32853f7c258a5cd227650889b38839fe9d"}, "phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.6.5", "1495bb014be12c9a9252eca04b9af54246f6b5c1e4cd1f30210cd00ec540cf8e", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.3", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.17.7", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "ef4fa50dd78364409039c99cf6f98ab5209b4c5f8796c17f4db118324f0db852"},
"mint": {:hex, :mint, "1.6.2", "af6d97a4051eee4f05b5500671d47c3a67dac7386045d87a904126fd4bbcea2e", [:mix], [{:castore, "~> 0.1.0 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:hpax, "~> 0.1.1 or ~> 0.2.0 or ~> 1.0", [hex: :hpax, repo: "hexpm", optional: false]}], "hexpm", "5ee441dffc1892f1ae59127f74afe8fd82fda6587794278d924e4d90ea3d63f9"}, "phoenix_live_view": {:hex, :phoenix_live_view, "0.17.9", "36b5aa812bc3ccd64c9630f6b3234d9ea21105493237e927aae19d0ba758f0db", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.1", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f7ebc3e0ba0c5f6b6996ed6c901ddbfdaba59a6d09b569e7cb2f2f7d693b4455"},
"mix_audit": {:hex, :mix_audit, "2.1.4", "0a23d5b07350cdd69001c13882a4f5fb9f90fbd4cbf2ebc190a2ee0d187ea3e9", [:make, :mix], [{:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:yaml_elixir, "~> 2.11", [hex: :yaml_elixir, repo: "hexpm", optional: false]}], "hexpm", "fd807653cc8c1cada2911129c7eb9e985e3cc76ebf26f4dd628bb25bbcaa7099"}, "phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.1", "ba04e489ef03763bf28a17eb2eaddc2c20c6d217e2150a61e3298b0f4c2012b5", [:mix], [], "hexpm", "81367c6d1eea5878ad726be80808eb5a787a23dee699f96e72b1109c57cdd8d9"},
"nimble_options": {:hex, :nimble_options, "1.1.1", "e3a492d54d85fc3fd7c5baf411d9d2852922f66e69476317787a7b2bb000a61b", [:mix], [], "hexpm", "821b2470ca9442c4b6984882fe9bb0389371b8ddec4d45a9504f00a66f650b44"}, "phoenix_view": {:hex, :phoenix_view, "1.1.2", "1b82764a065fb41051637872c7bd07ed2fdb6f5c3bd89684d4dca6e10115c95a", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "7ae90ad27b09091266f6adbb61e1d2516a7c3d7062c6789d46a7554ec40f3a56"},
"nimble_parsec": {:hex, :nimble_parsec, "1.4.0", "51f9b613ea62cfa97b25ccc2c1b4216e81df970acd8e16e8d1bdc58fef21370d", [:mix], [], "hexpm", "9c565862810fb383e9838c1dd2d7d2c437b3d13b267414ba6af33e50d2d1cf28"}, "plug": {:hex, :plug, "1.13.6", "187beb6b67c6cec50503e940f0434ea4692b19384d47e5fdfd701e93cadb4cc2", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "02b9c6b9955bce92c829f31d6284bf53c591ca63c4fb9ff81dfd0418667a34ff"},
"nimble_pool": {:hex, :nimble_pool, "1.1.0", "bf9c29fbdcba3564a8b800d1eeb5a3c58f36e1e11d7b7fb2e084a643f645f06b", [:mix], [], "hexpm", "af2e4e6b34197db81f7aad230c1118eac993acc0dae6bc83bac0126d4ae0813a"}, "plug_cowboy": {:hex, :plug_cowboy, "2.5.2", "62894ccd601cf9597e2c23911ff12798a8a18d237e9739f58a6b04e4988899fe", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.7", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "ea6e87f774c8608d60c8d34022a7d073bd7680a0a013f049fc62bf35efea1044"},
"octo_fetch": {:hex, :octo_fetch, "0.4.0", "074b5ecbc08be10b05b27e9db08bc20a3060142769436242702931c418695b19", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "~> 1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm", "cf8be6f40cd519d7000bb4e84adcf661c32e59369ca2827c4e20042eda7a7fc6"}, "plug_crypto": {:hex, :plug_crypto, "1.2.2", "05654514ac717ff3a1843204b424477d9e60c143406aa94daf2274fdd280794d", [:mix], [], "hexpm", "87631c7ad914a5a445f0a3809f99b079113ae4ed4b867348dd9eec288cecb6db"},
"parse_trans": {:hex, :parse_trans, "3.4.1", "6e6aa8167cb44cc8f39441d05193be6e6f4e7c2946cb2759f015f8c56b76e5ff", [:rebar3], [], "hexpm", "620a406ce75dada827b82e453c19cf06776be266f5a67cff34e1ef2cbb60e49a"}, "postgrex": {:hex, :postgrex, "0.16.2", "0f83198d0e73a36e8d716b90f45f3bde75b5eebf4ade4f43fa1f88c90a812f74", [:mix], [{:connection, "~> 1.1", [hex: :connection, repo: "hexpm", optional: false]}, {:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}], "hexpm", "a9ea589754d9d4d076121090662b7afe155b374897a6550eb288f11d755acfa0"},
"peep": {:hex, :peep, "3.2.0", "569d7b1f1a8c8f3e72327b42c0b9d4284db9d4ca53514bcf9c8358ee70f45ff8", [:mix], [{:nimble_options, "~> 1.1", [hex: :nimble_options, repo: "hexpm", optional: false]}, {:plug, "~> 1.16", [hex: :plug, repo: "hexpm", optional: true]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "267ffde5b7261b132f4e6a0b602d789be176fe8160fad788af9ca0de2c9a9180"},
"pg_ranges": {:hex, :pg_ranges, "1.1.1", "304da41118282eb81ffaefc3195e379afe139867fdc5171626aec9c83d360537", [:mix], [{:decimal, "~> 2.1", [hex: :decimal, repo: "hexpm", optional: false]}, {:ecto_sql, "~> 3.11", [hex: :ecto_sql, repo: "hexpm", optional: false]}, {:postgrex, ">= 0.0.0", [hex: :postgrex, repo: "hexpm", optional: false]}], "hexpm", "d49c28628c2276d4964f0ced6cc8c140a62af6eeb05c1b86a23afed8b3a5db8c"},
"phoenix": {:hex, :phoenix, "1.7.14", "a7d0b3f1bc95987044ddada111e77bd7f75646a08518942c72a8440278ae7825", [:mix], [{:castore, ">= 0.0.0", [hex: :castore, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix_pubsub, "~> 2.1", [hex: :phoenix_pubsub, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.7", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:plug_crypto, "~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:websock_adapter, "~> 0.5.3", [hex: :websock_adapter, repo: "hexpm", optional: false]}], "hexpm", "c7859bc56cc5dfef19ecfc240775dae358cbaa530231118a9e014df392ace61a"},
"phoenix_ecto": {:hex, :phoenix_ecto, "4.6.2", "3b83b24ab5a2eb071a20372f740d7118767c272db386831b2e77638c4dcc606d", [:mix], [{:ecto, "~> 3.5", [hex: :ecto, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.1", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:plug, "~> 1.9", [hex: :plug, repo: "hexpm", optional: false]}, {:postgrex, "~> 0.16 or ~> 1.0", [hex: :postgrex, repo: "hexpm", optional: true]}], "hexpm", "3f94d025f59de86be00f5f8c5dd7b5965a3298458d21ab1c328488be3b5fcd59"},
"phoenix_html": {:hex, :phoenix_html, "4.1.1", "4c064fd3873d12ebb1388425a8f2a19348cef56e7289e1998e2d2fa758aa982e", [:mix], [], "hexpm", "f2f2df5a72bc9a2f510b21497fd7d2b86d932ec0598f0210fed4114adc546c6f"},
"phoenix_live_dashboard": {:hex, :phoenix_live_dashboard, "0.8.4", "4508e481f791ce62ec6a096e13b061387158cbeefacca68c6c1928e1305e23ed", [:mix], [{:ecto, "~> 3.6.2 or ~> 3.7", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_mysql_extras, "~> 0.5", [hex: :ecto_mysql_extras, repo: "hexpm", optional: true]}, {:ecto_psql_extras, "~> 0.7", [hex: :ecto_psql_extras, repo: "hexpm", optional: true]}, {:ecto_sqlite3_extras, "~> 1.1.7 or ~> 1.2.0", [hex: :ecto_sqlite3_extras, repo: "hexpm", optional: true]}, {:mime, "~> 1.6 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:phoenix_live_view, "~> 0.19 or ~> 1.0", [hex: :phoenix_live_view, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "2984aae96994fbc5c61795a73b8fb58153b41ff934019cfb522343d2d3817d59"},
"phoenix_live_view": {:hex, :phoenix_live_view, "0.20.17", "f396bbdaf4ba227b82251eb75ac0afa6b3da5e509bc0d030206374237dfc9450", [:mix], [{:floki, "~> 0.36", [hex: :floki, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:phoenix, "~> 1.6.15 or ~> 1.7.0", [hex: :phoenix, repo: "hexpm", optional: false]}, {:phoenix_html, "~> 3.3 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: false]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}, {:phoenix_view, "~> 2.0", [hex: :phoenix_view, repo: "hexpm", optional: true]}, {:plug, "~> 1.15", [hex: :plug, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.2 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a61d741ffb78c85fdbca0de084da6a48f8ceb5261a79165b5a0b59e5f65ce98b"},
"phoenix_pubsub": {:hex, :phoenix_pubsub, "2.1.3", "3168d78ba41835aecad272d5e8cd51aa87a7ac9eb836eabc42f6e57538e3731d", [:mix], [], "hexpm", "bba06bc1dcfd8cb086759f0edc94a8ba2bc8896d5331a1e2c2902bf8e36ee502"},
"phoenix_template": {:hex, :phoenix_template, "1.0.4", "e2092c132f3b5e5b2d49c96695342eb36d0ed514c5b252a77048d5969330d639", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}], "hexpm", "2c0c81f0e5c6753faf5cca2f229c9709919aba34fab866d3bc05060c9c444206"},
"phoenix_view": {:hex, :phoenix_view, "2.0.4", "b45c9d9cf15b3a1af5fb555c674b525391b6a1fe975f040fb4d913397b31abf4", [:mix], [{:phoenix_html, "~> 2.14.2 or ~> 3.0 or ~> 4.0", [hex: :phoenix_html, repo: "hexpm", optional: true]}, {:phoenix_template, "~> 1.0", [hex: :phoenix_template, repo: "hexpm", optional: false]}], "hexpm", "4e992022ce14f31fe57335db27a28154afcc94e9983266835bb3040243eb620b"},
"plug": {:hex, :plug, "1.16.1", "40c74619c12f82736d2214557dedec2e9762029b2438d6d175c5074c933edc9d", [:mix], [{:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:plug_crypto, "~> 1.1.1 or ~> 1.2 or ~> 2.0", [hex: :plug_crypto, repo: "hexpm", optional: false]}, {:telemetry, "~> 0.4.3 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "a13ff6b9006b03d7e33874945b2755253841b238c34071ed85b0e86057f8cddc"},
"plug_cowboy": {:hex, :plug_cowboy, "2.7.2", "fdadb973799ae691bf9ecad99125b16625b1c6039999da5fe544d99218e662e4", [:mix], [{:cowboy, "~> 2.7", [hex: :cowboy, repo: "hexpm", optional: false]}, {:cowboy_telemetry, "~> 0.3", [hex: :cowboy_telemetry, repo: "hexpm", optional: false]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}], "hexpm", "245d8a11ee2306094840c000e8816f0cbed69a23fc0ac2bcf8d7835ae019bb2f"},
"plug_crypto": {:hex, :plug_crypto, "2.1.0", "f44309c2b06d249c27c8d3f65cfe08158ade08418cf540fd4f72d4d6863abb7b", [:mix], [], "hexpm", "131216a4b030b8f8ce0f26038bc4421ae60e4bb95c5cf5395e1421437824c4fa"},
"postgrex": {:hex, :postgrex, "0.19.1", "73b498508b69aded53907fe48a1fee811be34cc720e69ef4ccd568c8715495ea", [:mix], [{:db_connection, "~> 2.1", [hex: :db_connection, repo: "hexpm", optional: false]}, {:decimal, "~> 1.5 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:table, "~> 0.1.0", [hex: :table, repo: "hexpm", optional: true]}], "hexpm", "8bac7885a18f381e091ec6caf41bda7bb8c77912bb0e9285212829afe5d8a8f8"},
"prom_ex": {:hex, :prom_ex, "1.10.0", "2fe14cd0b2f7f8688280b02861c58da9624571f82a878b203825fb2bec206195", [:mix], [{:absinthe, ">= 1.7.0", [hex: :absinthe, repo: "hexpm", optional: true]}, {:broadway, ">= 1.1.0", [hex: :broadway, repo: "hexpm", optional: true]}, {:ecto, ">= 3.11.0", [hex: :ecto, repo: "hexpm", optional: true]}, {:finch, "~> 0.18", [hex: :finch, repo: "hexpm", optional: false]}, {:jason, "~> 1.4", [hex: :jason, repo: "hexpm", optional: false]}, {:oban, ">= 2.10.0", [hex: :oban, repo: "hexpm", optional: true]}, {:octo_fetch, "~> 0.4", [hex: :octo_fetch, repo: "hexpm", optional: false]}, {:peep, "~> 3.0", [hex: :peep, repo: "hexpm", optional: false]}, {:phoenix, ">= 1.7.0", [hex: :phoenix, repo: "hexpm", optional: true]}, {:phoenix_live_view, ">= 0.20.0", [hex: :phoenix_live_view, repo: "hexpm", optional: true]}, {:plug, ">= 1.16.0", [hex: :plug, repo: "hexpm", optional: true]}, {:plug_cowboy, ">= 2.6.0", [hex: :plug_cowboy, repo: "hexpm", optional: false]}, {:telemetry, ">= 1.0.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}, {:telemetry_metrics_prometheus_core, "~> 1.2", [hex: :telemetry_metrics_prometheus_core, repo: "hexpm", optional: false]}, {:telemetry_poller, "~> 1.1", [hex: :telemetry_poller, repo: "hexpm", optional: false]}], "hexpm", "55d6ca87519b14202570dda5f29bf3f52e14b940eaf2ddcd89ad41347fa5781a"},
"ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"}, "ranch": {:hex, :ranch, "1.8.0", "8c7a100a139fd57f17327b6413e4167ac559fbc04ca7448e9be9057311597a1d", [:make, :rebar3], [], "hexpm", "49fbcfd3682fab1f5d109351b61257676da1a2fdbe295904176d5e521a2ddfe5"},
"sobelow": {:hex, :sobelow, "0.13.0", "218afe9075904793f5c64b8837cc356e493d88fddde126a463839351870b8d1e", [:mix], [{:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "cd6e9026b85fc35d7529da14f95e85a078d9dd1907a9097b3ba6ac7ebbe34a0d"}, "telemetry": {:hex, :telemetry, "1.1.0", "a589817034a27eab11144ad24d5c0f9fab1f58173274b1e9bae7074af9cbee51", [:rebar3], [], "hexpm", "b727b2a1f75614774cff2d7565b64d0dfa5bd52ba517f16543e6fc7efcc0df48"},
"ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.7", "354c321cf377240c7b8716899e182ce4890c5938111a1296add3ec74cf1715df", [:make, :mix, :rebar3], [], "hexpm", "fe4c190e8f37401d30167c8c405eda19469f34577987c76dde613e838bbc67f8"}, "telemetry_metrics": {:hex, :telemetry_metrics, "0.6.1", "315d9163a1d4660aedc3fee73f33f1d355dcc76c5c3ab3d59e76e3edf80eef1f", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "7be9e0871c41732c233be71e4be11b96e56177bf15dde64a8ac9ce72ac9834c6"},
"telemetry": {:hex, :telemetry, "1.2.1", "68fdfe8d8f05a8428483a97d7aab2f268aaff24b49e0f599faa091f1d4e7f61c", [:rebar3], [], "hexpm", "dad9ce9d8effc621708f99eac538ef1cbe05d6a874dd741de2e689c47feafed5"}, "telemetry_poller": {:hex, :telemetry_poller, "1.0.0", "db91bb424e07f2bb6e73926fcafbfcbcb295f0193e0a00e825e589a0a47e8453", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "b3a24eafd66c3f42da30fc3ca7dda1e9d546c12250a2d60d7b81d264fbec4f6e"},
"telemetry_metrics": {:hex, :telemetry_metrics, "1.0.0", "29f5f84991ca98b8eb02fc208b2e6de7c95f8bb2294ef244a176675adc7775df", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "f23713b3847286a534e005126d4c959ebcca68ae9582118ce436b521d1d47d5d"},
"telemetry_metrics_prometheus_core": {:hex, :telemetry_metrics_prometheus_core, "1.2.1", "c9755987d7b959b557084e6990990cb96a50d6482c683fb9622a63837f3cd3d8", [:mix], [{:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}, {:telemetry_metrics, "~> 0.6 or ~> 1.0", [hex: :telemetry_metrics, repo: "hexpm", optional: false]}], "hexpm", "5e2c599da4983c4f88a33e9571f1458bf98b0cf6ba930f1dc3a6e8cf45d5afb6"},
"telemetry_poller": {:hex, :telemetry_poller, "1.1.0", "58fa7c216257291caaf8d05678c8d01bd45f4bdbc1286838a28c4bb62ef32999", [:rebar3], [{:telemetry, "~> 1.0", [hex: :telemetry, repo: "hexpm", optional: false]}], "hexpm", "9eb9d9cbfd81cbd7cdd24682f8711b6e2b691289a0de6826e58452f28c103c8f"},
"tesla": {:hex, :tesla, "1.12.1", "fe2bf4250868ee72e5d8b8dfa408d13a00747c41b7237b6aa3b9a24057346681", [:mix], [{:castore, "~> 0.1 or ~> 1.0", [hex: :castore, repo: "hexpm", optional: true]}, {:exjsx, ">= 3.0.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:finch, "~> 0.13", [hex: :finch, repo: "hexpm", optional: true]}, {:fuse, "~> 2.4", [hex: :fuse, repo: "hexpm", optional: true]}, {:gun, ">= 1.0.0", [hex: :gun, repo: "hexpm", optional: true]}, {:hackney, "~> 1.6", [hex: :hackney, repo: "hexpm", optional: true]}, {:ibrowse, "4.4.2", [hex: :ibrowse, repo: "hexpm", optional: true]}, {:jason, ">= 1.0.0", [hex: :jason, repo: "hexpm", optional: true]}, {:mime, "~> 1.0 or ~> 2.0", [hex: :mime, repo: "hexpm", optional: false]}, {:mint, "~> 1.0", [hex: :mint, repo: "hexpm", optional: true]}, {:msgpax, "~> 2.3", [hex: :msgpax, repo: "hexpm", optional: true]}, {:poison, ">= 1.0.0", [hex: :poison, repo: "hexpm", optional: true]}, {:telemetry, "~> 0.4 or ~> 1.0", [hex: :telemetry, repo: "hexpm", optional: true]}], "hexpm", "2391efc6243d37ead43afd0327b520314c7b38232091d4a440c1212626fdd6e7"},
"testcontainers": {:hex, :testcontainers, "1.10.5", "53c8af199197279c7ac48537922969798bf4fbf3a9f3f71ac0cef03234f60209", [:mix], [{:ecto, "~> 3.3", [hex: :ecto, repo: "hexpm", optional: true]}, {:ecto_sql, "~> 3.3", [hex: :ecto_sql, repo: "hexpm", optional: true]}, {:elixir_uuid, "~> 1.2", [hex: :elixir_uuid, repo: "hexpm", optional: false]}, {:ex_docker_engine_api, "~> 1.43.2", [hex: :ex_docker_engine_api, repo: "hexpm", optional: false]}, {:fs, "~> 8.6", [hex: :fs, repo: "hexpm", optional: false]}], "hexpm", "c65ef9b670e204abb11fbf37c7f4ef9fcc1c4b018c01eac6f4f111409a9ddf41"},
"unicode_util_compat": {:hex, :unicode_util_compat, "0.7.0", "bc84380c9ab48177092f43ac89e4dfa2c6d62b40b8bd132b1059ecc7232f9a78", [:rebar3], [], "hexpm", "25eee6d67df61960cf6a794239566599b09e17e668d3700247bc498638152521"},
"websock": {:hex, :websock, "0.5.3", "2f69a6ebe810328555b6fe5c831a851f485e303a7c8ce6c5f675abeb20ebdadc", [:mix], [], "hexpm", "6105453d7fac22c712ad66fab1d45abdf049868f253cf719b625151460b8b453"},
"websock_adapter": {:hex, :websock_adapter, "0.5.7", "65fa74042530064ef0570b75b43f5c49bb8b235d6515671b3d250022cb8a1f9e", [:mix], [{:bandit, ">= 0.6.0", [hex: :bandit, repo: "hexpm", optional: true]}, {:plug, "~> 1.14", [hex: :plug, repo: "hexpm", optional: false]}, {:plug_cowboy, "~> 2.6", [hex: :plug_cowboy, repo: "hexpm", optional: true]}, {:websock, "~> 0.5", [hex: :websock, repo: "hexpm", optional: false]}], "hexpm", "d0f478ee64deddfec64b800673fd6e0c8888b079d9f3444dd96d2a98383bdbd1"},
"yamerl": {:hex, :yamerl, "0.10.0", "4ff81fee2f1f6a46f1700c0d880b24d193ddb74bd14ef42cb0bcf46e81ef2f8e", [:rebar3], [], "hexpm", "346adb2963f1051dc837a2364e4acf6eb7d80097c0f53cbdc3046ec8ec4b4e6e"},
"yaml_elixir": {:hex, :yaml_elixir, "2.11.0", "9e9ccd134e861c66b84825a3542a1c22ba33f338d82c07282f4f1f52d847bd50", [:mix], [{:yamerl, "~> 0.10", [hex: :yamerl, repo: "hexpm", optional: false]}], "hexpm", "53cc28357ee7eb952344995787f4bb8cc3cecbf189652236e9b163e8ce1bc242"},
} }

View File

@@ -1,2 +0,0 @@
#!/usr/bin/env bash
elixir --name ${HOSTNAME}@$(hostname -i | cut -d ' ' -f1) --cookie ${1} -S mix phx.server

View File

@@ -1,2 +0,0 @@
#!/usr/bin/env bash
iex --name ex_trainer_remote@127.0.0.1 --hidden --cookie local-cookie --remsh ${HOSTNAME}@$(hostname -i | cut -d ' ' -f1)

View File

@@ -1,5 +0,0 @@
#!/bin/sh
set -eu
cd -P -- "$(dirname -- "$0")"
exec ./wabanex eval Wabanex.Release.migrate

View File

@@ -1 +0,0 @@
call "%~dp0\wabanex" eval Wabanex.Release.migrate

View File

@@ -1,5 +0,0 @@
#!/bin/sh
set -eu
cd -P -- "$(dirname -- "$0")"
PHX_SERVER=true exec ./wabanex start

View File

@@ -1,2 +0,0 @@
set PHX_SERVER=true
call "%~dp0\wabanex" start

View File

@@ -11,7 +11,6 @@ defmodule WabanexWeb.Schema.Types.Custom.DateRangeTest do
import_types Types.Custom.DateRange import_types Types.Custom.DateRange
query do query do
field :everything, :string, resolve: fn _, _, _ -> "is awesome" end
end end
end end
@@ -29,7 +28,6 @@ defmodule WabanexWeb.Schema.Types.Custom.DateRangeTest do
test "serialize a list of dates as a list of ISO8601 date strings" do test "serialize a list of dates as a list of ISO8601 date strings" do
assert "1978-12-15,1980-02-13" == serialize(:date_range, [~D[1978-12-15], ~D[1980-02-13]]) assert "1978-12-15,1980-02-13" == serialize(:date_range, [~D[1978-12-15], ~D[1980-02-13]])
assert "1978-12-15," == serialize(:date_range, [~D[1978-12-15], nil]) assert "1978-12-15," == serialize(:date_range, [~D[1978-12-15], nil])
assert "1978-12-15," == serialize(:date_range, [~D[1978-12-15], :unbound])
end end
test "serialize a postgres range as a list of ISO8601 date strings" do test "serialize a postgres range as a list of ISO8601 date strings" do
@@ -37,7 +35,6 @@ defmodule WabanexWeb.Schema.Types.Custom.DateRangeTest do
serialize(:date_range, DateRange.new(~D[1978-12-15], ~D[1980-02-13])) serialize(:date_range, DateRange.new(~D[1978-12-15], ~D[1980-02-13]))
assert "1978-12-15," == serialize(:date_range, DateRange.new(~D[1978-12-15], nil)) assert "1978-12-15," == serialize(:date_range, DateRange.new(~D[1978-12-15], nil))
assert "1978-12-15," == serialize(:date_range, DateRange.new(~D[1978-12-15], :unbound))
end end
test "can be parsed from a string of ISO8601" do test "can be parsed from a string of ISO8601" do