Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: Searching for implementations with keys #17

Open
wants to merge 15 commits into
base: main
Choose a base branch
from
296 changes: 111 additions & 185 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -1,197 +1,123 @@
# Created with GitHubActions version 0.2.1
name: CI

on:
pull_request:
push:
branches:
- main

env:
CACHE_PREFIX_DEPS: v1-deps
CACHE_PREFIX_BUILD: v1-_build
CACHE_PREFIX_DIALYZER: v1-dialyzer

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
on:
- pull_request
- push
jobs:
mix_test:
name: mix test (Erlang/OTP ${{matrix.otp}} | Elixir ${{matrix.elixir}} | Alpine ${{ matrix.alpine }})
linux:
name: Test on Ubuntu (Elixir ${{ matrix.elixir }}, OTP ${{ matrix.otp }})
runs-on: ubuntu-latest
container: hexpm/elixir:${{ matrix.elixir }}-erlang-${{ matrix.otp }}-alpine-${{ matrix.alpine }}
env:
MIX_ENV: test
VERSION_ALPINE: ${{ matrix.alpine }}
VERSION_ELIXIR: ${{ matrix.elixir }}
VERSION_OTP: ${{ matrix.otp }}
strategy:
fail-fast: false
matrix:
include:
- alpine: 3.11.6
elixir: 1.7.4
otp: 20.3.8.19
- alpine: 3.11.6
elixir: 1.8.2
otp: 20.3.8.19
- alpine: 3.11.6
elixir: 1.9.4
otp: 20.3.8.19
- alpine: 3.11.6
elixir: 1.9.4
otp: 21.3.8.16
- alpine: 3.11.6
elixir: 1.10.3
otp: 21.3.8.16
- alpine: 3.11.6
elixir: 1.11.2
otp: 22.3.4.3
- alpine: 3.11.6
elixir: 1.11.2
otp: 23.0.2
- alpine: 3.14.0
elixir: 1.12.3
otp: 24.1.1
steps:
- uses: actions/checkout@v2

- name: Cache - deps/
uses: actions/cache@v1
with:
path: deps/
key: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-

- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get --only "$MIX_ENV"

- name: Cache - _build/
uses: actions/cache@v1
with:
path: _build/
key: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-

- run: mix compile --warnings-as-errors
- run: mix test

coverage:
name: Collect Test Coverage
runs-on: ubuntu-latest
container: hexpm/elixir:1.11.2-erlang-22.3.4.3-alpine-3.11.6
env:
MIX_ENV: test
VERSION_ALPINE: 3.11.6
VERSION_ELIXIR: 1.11.2
VERSION_OTP: 22.3.4.3
steps:
- name: Install git (required for mix coveralls.github)
run: apk add --no-cache git

# mix coveralls.github uses git to fetch the pr head so we ensure the whole history is available
- uses: actions/checkout@v2
with:
fetch-depth: 0

- name: Cache - deps/
uses: actions/cache@v1
with:
path: deps/
key: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP}}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP}}-

- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get --only "$MIX_ENV"

- name: Cache - _build/
uses: actions/cache@v1
with:
path: _build/
key: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-

- run: mix compile --warnings-as-errors
- run: mix coveralls.github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

check_style:
name: Check Style
runs-on: ubuntu-latest
container: hexpm/elixir:1.11.2-erlang-22.3.4.3-alpine-3.11.6
env:
MIX_ENV: dev
VERSION_ALPINE: 3.11.6
VERSION_ELIXIR: 1.11.2
VERSION_OTP: 22.3.4.3
elixir:
- '1.7.4'
- '1.8.2'
- '1.9.4'
- '1.10.4'
- '1.11.4'
- '1.12.3'
- '1.13.4'
- '1.14.0'
otp:
- '20.3'
- '21.3'
- '22.3'
- '23.3'
- '24.3'
- '25.1'
exclude:
- elixir: '1.7.4'
otp: '23.3'
- elixir: '1.7.4'
otp: '24.3'
- elixir: '1.7.4'
otp: '25.1'
- elixir: '1.8.2'
otp: '23.3'
- elixir: '1.8.2'
otp: '24.3'
- elixir: '1.8.2'
otp: '25.1'
- elixir: '1.9.4'
otp: '23.3'
- elixir: '1.9.4'
otp: '24.3'
- elixir: '1.9.4'
otp: '25.1'
- elixir: '1.10.4'
otp: '20.3'
- elixir: '1.10.4'
otp: '24.3'
- elixir: '1.10.4'
otp: '25.1'
- elixir: '1.11.4'
otp: '20.3'
- elixir: '1.11.4'
otp: '25.1'
- elixir: '1.12.3'
otp: '20.3'
- elixir: '1.12.3'
otp: '21.3'
- elixir: '1.12.3'
otp: '25.1'
- elixir: '1.13.4'
otp: '20.3'
- elixir: '1.13.4'
otp: '21.3'
- elixir: '1.14.0'
otp: '20.3'
- elixir: '1.14.0'
otp: '21.3'
- elixir: '1.14.0'
otp: '22.3'
steps:
- uses: actions/checkout@v2

- name: Cache - deps/
uses: actions/cache@v1
- name: Checkout
uses: actions/checkout@v3
- name: Setup Elixir
uses: erlef/setup-beam@v1
with:
path: deps/
key: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-

- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get --only "$MIX_ENV"

- name: Cache - _build/
uses: actions/cache@v1
with:
path: _build/
key: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-

- run: mix compile --warnings-as-errors
- run: mix format --check-formatted
- run: mix credo

check_types:
name: Check Types
runs-on: ubuntu-latest
container: hexpm/elixir:1.11.2-erlang-22.3.4.3-alpine-3.11.6
env:
MIX_ENV: dev
VERSION_ALPINE: 3.11.6
VERSION_ELIXIR: 1.11.2
VERSION_OTP: 22.3.4.3
steps:
- uses: actions/checkout@v2

- name: Cache - deps/
uses: actions/cache@v1
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
- name: Restore deps
uses: actions/cache@v2
with:
path: deps/
key: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_DEPS }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-

- name: Install Dependencies
run: |
mix local.rebar --force
mix local.hex --force
mix deps.get --only "$MIX_ENV"

- name: Cache - _build/
uses: actions/cache@v1
path: deps
key: deps-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Restore _build
uses: actions/cache@v2
with:
path: _build/
key: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-${{ hashFiles('**/mix.lock') }}
restore-keys: ${{ env.CACHE_PREFIX_BUILD }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}-

- run: mix compile --warnings-as-errors

- name: Cache - Dialyzer PLTs
uses: actions/cache@v1
path: _build
key: _build-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
- name: Restore .dialyzer
uses: actions/cache@v2
with:
path: .dialyzer/
key: ${{ env.CACHE_PREFIX_DIALYZER }}-env:${{ env.MIX_ENV }}-alpine:${{ env.VERSION_ALPINE }}-elixir:${{ env.VERSION_ELIXIR }}-otp:${{ env.VERSION_OTP }}

- run: mix dialyzer
path: .dialyzer
key: .dialyzer-${{ runner.os }}-${{ matrix.elixir }}-${{ matrix.otp }}-${{ hashFiles(format('{0}{1}', github.workspace, '/mix.lock')) }}
if: ${{ contains(matrix.elixir, '1.14.0') && contains(matrix.otp, '25.1') }}
- name: Get dependencies
run: mix deps.get
- name: Compile dependencies
run: MIX_ENV=test mix deps.compile
- name: Compile project
run: MIX_ENV=test mix compile --warnings-as-errors
- name: Check unused dependencies
if: ${{ contains(matrix.elixir, '1.14.0') && contains(matrix.otp, '25.1') }}
run: MIX_ENV=test mix deps.unlock --check-unused
- name: Check code format
if: ${{ contains(matrix.elixir, '1.14.0') && contains(matrix.otp, '25.1') }}
run: MIX_ENV=test mix format --check-formatted
- name: Lint code
if: ${{ contains(matrix.elixir, '1.14.0') && contains(matrix.otp, '25.1') }}
run: MIX_ENV=test mix credo --strict
- name: Run tests
run: MIX_ENV=test mix test
if: ${{ !(contains(matrix.elixir, '1.14.0') && contains(matrix.otp, '25.1')) }}
- name: Run tests with coverage
run: MIX_ENV=test mix coveralls.github
if: ${{ contains(matrix.elixir, '1.14.0') && contains(matrix.otp, '25.1') }}
- name: Static code analysis
run: mix dialyzer
if: ${{ contains(matrix.elixir, '1.14.0') && contains(matrix.otp, '25.1') }}
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
elixir 1.12.2
erlang 23.3.4.5
elixir 1.14.0-otp-25
erlang 25.1
2 changes: 1 addition & 1 deletion config/config.exs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
use Mix.Config
import Config

import_config "#{Mix.env()}.exs"
2 changes: 1 addition & 1 deletion config/dev.exs
Original file line number Diff line number Diff line change
@@ -1 +1 @@
use Mix.Config
import Mix.Config
2 changes: 1 addition & 1 deletion config/test.exs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use Mix.Config
import Config

config :knigge,
delegate_at_runtime?: false
24 changes: 19 additions & 5 deletions lib/knigge/implementation.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,15 +9,21 @@ defmodule Knigge.Implementation do

alias Knigge.Options

def fetch!(%Options{implementation: {:config, otp_app, key}, default: default}) do
if is_nil(default) do
Application.fetch_env!(otp_app, key)
def fetch!(%Options{implementation: {:config, otp_app, [key | keys]}, default: default}) do
module = otp_app |> env!(key, default) |> get(keys)

if is_nil(module) do
raise ArgumentError,
message: """
could not fetch application environment #{inspect([key | keys])} \
for application #{inspect(otp_app)}\
"""
else
Application.get_env(otp_app, key, default)
module
end
end

def fetch!(%Options{implementation: implementation}) do
def fetch!(%Options{implementation: implementation}) when is_atom(implementation) do
implementation
end

Expand All @@ -26,4 +32,12 @@ defmodule Knigge.Implementation do
|> Knigge.options!()
|> Knigge.Implementation.fetch!()
end

defp env!(otp_app, key, nil), do: Application.fetch_env!(otp_app, key)

defp env!(otp_app, key, default), do: Application.get_env(otp_app, key, default)

defp get(data, []), do: data

defp get(data, keys), do: get_in(data, keys)
end
Loading