Skip to content

Commit

Permalink
Merge branch 'main' into apb/data-source
Browse files Browse the repository at this point in the history
  • Loading branch information
APB9785 committed Nov 17, 2023
2 parents 7260d31 + 62ca059 commit f0d33bb
Show file tree
Hide file tree
Showing 26 changed files with 1,185 additions and 156 deletions.
66 changes: 38 additions & 28 deletions .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,27 +11,36 @@ permissions:

jobs:
test:
name: test (OTP ${{matrix.otp}} | Elixir ${{matrix.elixir}})

env:
MIX_ENV: test
MDEX_BUILD: 1
name: "test: OTP ${{matrix.otp}} | Elixir ${{matrix.elixir}} | Phoenix ${{matrix.phoenix-version}} | LiveView ${{matrix.phoenix-live-view-version}}"

strategy:
matrix:
include:
- elixir: "1.13.0"
otp: "23"
# minimum required versions
- otp: "23"
elixir: "1.13.0"
phoenix-version: "1.7.0"
phoenix-live-view-version: "0.19.0"

# latest
- otp: "26"
elixir: "1.15"
phoenix-version: "~> 1.7"
phoenix-live-view-version: "~> 0.20"

- elixir: "1.15.1"
otp: "26"
env:
MIX_ENV: test
MDEX_BUILD: 1
PHOENIX_VERSION: ${{matrix.phoenix-version}}
PHOENIX_LIVE_VIEW_VERSION: ${{matrix.phoenix-live-view-version}}

runs-on: ubuntu-20.04

services:
postgres:
image: postgres:13.1
env:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
options: >-
--health-cmd pg_isready
Expand All @@ -48,8 +57,8 @@ jobs:
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}

- name: Cache mix deps
uses: actions/cache@v3
Expand All @@ -58,29 +67,31 @@ jobs:
path: |
deps
_build
key: mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }}
key: mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ matrix.phoenix-version }}-${{ matrix.phoenix-live-view-version }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-
mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ matrix.phoenix-version }}-${{ matrix.phoenix-live-view-version }}-${{ hashFiles('**/mix.lock') }}
- run: mix do deps.get, deps.compile
if: steps.cache-deps.outputs.cache-hit != 'true'

- run: mix tailwind.install

- run: mix test

quality:
name: quality (OTP ${{matrix.otp}} | Elixir ${{matrix.elixir}})

env:
MIX_ENV: dev
MDEX_BUILD: 1
name: "quality: OTP ${{matrix.otp}} | Elixir ${{matrix.elixir}} | Phoenix ${{matrix.phoenix-version}} | LiveView ${{matrix.phoenix-live-view-version}}"

strategy:
matrix:
include:
- elixir: "1.15.1"
otp: "26"
# latest
- otp: "26"
elixir: "1.15"
phoenix-version: "~> 1.7"
phoenix-live-view-version: "~> 0.20"

env:
MIX_ENV: dev
MDEX_BUILD: 1

runs-on: ubuntu-20.04

Expand All @@ -91,8 +102,8 @@ jobs:
- name: Set up Elixir
uses: erlef/setup-beam@v1
with:
elixir-version: ${{ matrix.elixir }}
otp-version: ${{ matrix.otp }}
elixir-version: ${{ matrix.elixir }}

- name: Cache mix deps
uses: actions/cache@v3
Expand All @@ -101,34 +112,33 @@ jobs:
path: |
deps
_build
key: mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }}
key: mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ matrix.phoenix-version }}-${{ matrix.phoenix-live-view-version }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-
mix-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ matrix.phoenix-version }}-${{ matrix.phoenix-live-view-version }}-${{ hashFiles('**/mix.lock') }}
- run: mix do deps.get, deps.compile
if: steps.cache-deps.outputs.cache-hit != 'true'

- name: Cache dialyzer
uses: actions/cache@v2
id: cache-plt
with:
path: priv/plts
key: dialyzer-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ hashFiles('**/mix.lock') }}
key: dialyzer-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ matrix.phoenix-version }}-${{ matrix.phoenix-live-view-version }}-${{ hashFiles('**/mix.lock') }}
restore-keys: |
dialyzer-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-
dialyzer-${{ env.MIX_ENV }}-${{ runner.os }}-${{ matrix.otp }}-${{ matrix.elixir }}-${{ matrix.phoenix-version }}-${{ matrix.phoenix-live-view-version }}-${{ hashFiles('**/mix.lock') }}
- name: Generate dialyzer plt
run: mix dialyzer --plt
if: steps.cache-plt.outputs.cache-hit != 'true'

- run: mix tailwind.install

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

- run: mix format --check-formatted

- run: mix deps.unlock --check-unused

- run: mix credo --strict

- run: mix dialyzer
- run: mix dialyzer --format github
21 changes: 21 additions & 0 deletions lib/beacon/content.ex
Original file line number Diff line number Diff line change
Expand Up @@ -1770,6 +1770,27 @@ defmodule Beacon.Content do
|> Repo.all()
end

@doc type: :error_pages
@spec list_error_pages_by(Site.t(), keyword(), keyword()) :: Layout.t() | nil
def list_error_pages_by(site, clauses, opts \\ []) when is_atom(site) and is_list(clauses) do
per_page = Keyword.get(opts, :per_page, 20)
preloads = Keyword.get(opts, :preloads, [])

filter_layout_id =
if layout_id = clauses[:layout_id] do
dynamic([ep], ep.layout_id == ^layout_id)
else
true
end

site
|> query_list_error_pages_base()
|> query_list_error_pages_limit(per_page)
|> query_list_error_pages_preloads(preloads)
|> where(^filter_layout_id)
|> Repo.all()
end

defp query_list_error_pages_base(site) do
from p in ErrorPage,
where: p.site == ^site,
Expand Down
13 changes: 2 additions & 11 deletions lib/beacon/content/page.ex
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ defmodule Beacon.Content.Page do
field :description, :string
field :template, :string
field :meta_tags, {:array, :map}, default: []
field :raw_schema, {:array, :map}, default: []
field :raw_schema, Beacon.Types.JsonArrayMap, default: []
field :order, :integer, default: 1
field :format, Beacon.Types.Atom, default: :heex
field :extra, :map, default: %{}
Expand Down Expand Up @@ -112,6 +112,7 @@ defmodule Beacon.Content.Page do
:title,
:description,
:meta_tags,
:raw_schema,
:format
])
|> cast(attrs, [:path], empty_values: [])
Expand All @@ -122,7 +123,6 @@ defmodule Beacon.Content.Page do
:format
])
|> validate_string([:path])
|> validate_raw_schema(attrs["raw_schema"])
|> remove_all_newlines([:description])
|> remove_empty_meta_attributes(:meta_tags)
|> Content.PageField.apply_changesets(page.site, extra_attrs)
Expand Down Expand Up @@ -173,13 +173,4 @@ defmodule Beacon.Content.Page do
|> Enum.reject(fn {_key, value} -> is_nil(value) || String.trim(value) == "" end)
|> Map.new()
end

defp validate_raw_schema(changeset, raw_schema) do
raw_schema = if raw_schema in ["", nil], do: "[]", else: raw_schema

case Jason.decode(raw_schema) do
{:ok, raw_schema} -> put_change(changeset, :raw_schema, raw_schema)
{:error, _} -> add_error(changeset, :raw_schema, "invalid schema")
end
end
end
37 changes: 25 additions & 12 deletions lib/beacon/loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -171,24 +171,32 @@ defmodule Beacon.Loader do
end

@doc false
def reload_module!(module, ast, file \\ "nofile") do
def reload_module!(module, ast, file \\ "nofile", failure_count \\ 0) do
:code.delete(module)
:code.purge(module)
[{^module, _}] = Code.compile_quoted(ast, file)
{:module, ^module} = Code.ensure_loaded(module)
:ok
rescue
e ->
message = """
failed to load module #{inspect(module)}
if failure_count >= 3 do
Logger.debug("failed to load module #{inspect(module)} after #{failure_count} tries.")

Got:
message = """
failed to load module #{inspect(module)}
#{Exception.message(e)}"],
Got:
"""
#{Exception.message(e)}
"""

reraise Beacon.LoaderError, [message: message], __STACKTRACE__
reraise Beacon.LoaderError, [message: message], __STACKTRACE__
else
Logger.debug("failed to load module #{inspect(module)}, retrying...")
:timer.sleep(100 * (failure_count * 2))
reload_module!(module, ast, file, failure_count + 1)
end
end

# too slow to run the css compiler on every test
Expand Down Expand Up @@ -307,14 +315,12 @@ defmodule Beacon.Loader do
e in UndefinedFunctionError ->
case {failure_count, e} do
{x, _} when x >= 10 ->
Logger.debug("failed to call #{inspect(module)} #{inspect(function)} 10 times.")
Logger.debug("failed to call #{inspect(module)} #{inspect(function)} after #{failure_count} tries.")
reraise e, __STACKTRACE__

{_, %UndefinedFunctionError{function: ^function, module: ^module}} ->
Logger.debug("failed to call #{inspect(module)} #{inspect(function)} with #{inspect(args)} for the #{failure_count + 1} time. Retrying.")

Logger.debug("failed to call #{inspect(module)} #{inspect(function)} with #{inspect(args)} for the #{failure_count + 1} time, retrying...")
:timer.sleep(100 * (failure_count * 2))

call_function_with_retry(module, function, args, failure_count + 1)

_ ->
Expand Down Expand Up @@ -392,7 +398,7 @@ defmodule Beacon.Loader do
:ok <- load_snippet_helpers(site),
:ok <- load_stylesheets(site),
{:ok, _module, _ast} <- Beacon.Loader.LayoutModuleLoader.load_layout!(layout),
:ok <- load_error_pages(site) do
:ok <- maybe_reload_error_pages(layout) do
:ok
else
_ -> raise Beacon.LoaderError, message: "failed to load resources for layout #{layout.title} of site #{layout.site}"
Expand Down Expand Up @@ -480,6 +486,13 @@ defmodule Beacon.Loader do
end
end

# we need to reload error pages bacause the layout is embeeded into those pages
defp maybe_reload_error_pages(layout) do
error_pages = Content.list_error_pages_by(layout.site, [layout_id: layout.id], per_page: :infinity, preloads: [:layout])
ErrorPageModuleLoader.load_error_pages!(error_pages, layout.site)
:ok
end

@doc false
# https://github.com/phoenixframework/phoenix_live_view/blob/8fedc6927fd937fe381553715e723754b3596a97/lib/phoenix_live_view/channel.ex#L435-L437
def exported?(m, f, a) do
Expand Down
2 changes: 2 additions & 0 deletions lib/beacon/loader/error_page_module_loader.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ defmodule Beacon.Loader.ErrorPageModuleLoader do
alias Beacon.Content.ErrorPage
alias Beacon.Loader

def load_error_pages!([] = _error_pages, _site), do: :skip

def load_error_pages!(error_pages, site) do
error_module = Loader.error_module_for_site(site)
layout_functions = Enum.map(error_pages, &build_layout_fn/1)
Expand Down
1 change: 0 additions & 1 deletion lib/beacon/pub_sub.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ defmodule Beacon.PubSub do
require Logger
alias Beacon.Content.Component
alias Beacon.Content.ErrorPage
alias Beacon.Content.ErrorPage
alias Beacon.Content.Layout
alias Beacon.Content.LiveData
alias Beacon.Content.Page
Expand Down
8 changes: 7 additions & 1 deletion lib/beacon/template/heex/json_encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,13 @@ defmodule Beacon.Template.HEEx.JSONEncoder do
"""
@spec encode(Beacon.Types.Site.t(), String.t(), map()) :: {:ok, [token()]} | {:error, String.t()}
def encode(site, template, assigns \\ %{}) when is_atom(site) and is_binary(template) and is_map(assigns) do
def encode(site, template, assigns \\ %{})

def encode(site, nil = _template, assigns) when is_atom(site) and is_map(assigns) do
encode(site, "", assigns)
end

def encode(site, template, assigns) when is_atom(site) and is_binary(template) and is_map(assigns) do
case Beacon.Template.HEEx.Tokenizer.tokenize(template) do
{:ok, tokens} -> {:ok, encode_tokens(tokens, site, assigns)}
error -> error
Expand Down
Loading

0 comments on commit f0d33bb

Please sign in to comment.