diff --git a/.github/workflows/formatting.yml b/.github/workflows/formatting.yml new file mode 100644 index 0000000..b854b5c --- /dev/null +++ b/.github/workflows/formatting.yml @@ -0,0 +1,23 @@ +name: Formatting +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] +permissions: + contents: read +jobs: + formatting: + permissions: + contents: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: erlef/setup-beam@v1 + with: + otp-version: "27" + elixir-version: "1.18.4" + - name: get dependencies + run: mix deps.get + - name: check formatting + run: mix format --check-formatted diff --git a/.github/workflows/linting.yml b/.github/workflows/linting.yml new file mode 100644 index 0000000..a53716d --- /dev/null +++ b/.github/workflows/linting.yml @@ -0,0 +1,33 @@ +name: Linting +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] +permissions: + contents: read +jobs: + credo: + permissions: + contents: read + security-events: write + actions: read + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: erlef/setup-beam@v1 + with: + otp-version: "27" + elixir-version: "1.18.4" + - name: get dependencies + run: mix deps.get + - name: compile dependencies + run: mix deps.compile + - name: compile + run: mix compile --warnings-as-errors + - name: credo + run: mix credo --format=sarif > credo_output.sarif + - name: upload sarif + uses: github/codeql-action/upload-sarif@v3 + with: + sarif_file: credo_output.sarif diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml new file mode 100644 index 0000000..375d301 --- /dev/null +++ b/.github/workflows/test.yml @@ -0,0 +1,40 @@ +name: Test +on: + push: + branches: ["main"] + pull_request: + branches: ["main"] +permissions: + contents: read +jobs: + test: + permissions: + contents: read + runs-on: ubuntu-latest + services: + postgres: + image: postgres:17 + ports: + - 5432:5432 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + options: >- + --health-cmd pg_isready + --health-interval 10s + --health-timeout 5s + --health-retries 5 + steps: + - uses: actions/checkout@v4 + - uses: erlef/setup-beam@v1 + with: + otp-version: "27" + elixir-version: "1.18.4" + - name: get dependencies + run: mix deps.get + - name: compile dependencies + run: MIX_ENV=test mix deps.compile + - name: compile + run: MIX_ENV=test mix compile --warnings-as-errors + - name: run tests + run: mix test diff --git a/config/dev.exs b/config/dev.exs index 5418e4b..03360d7 100644 --- a/config/dev.exs +++ b/config/dev.exs @@ -84,10 +84,6 @@ config :swoosh, :api_client, false # retries: 2, # no_mx_lookups: false -# Import dev local env specific config. This must remain at the bottom -# of this file so it overrides the configuration defined above. -import_config "dev.local.exs" - # Configure CQRS config :reply_express, ReplyExpress.Commanded, event_store: [ @@ -101,3 +97,9 @@ config :reply_express, ReplyExpress.EventStore, column_data_type: "jsonb", serializer: EventStore.JsonbSerializer, types: EventStore.PostgresTypes + +# Import dev local env specific config. This must remain at the bottom +# of this file so it overrides the configuration defined above. +if File.exists?("dev.local.exs") do + import_config "dev.local.exs" +end diff --git a/lib/reply_express/accounts/aggregates/team.ex b/lib/reply_express/accounts/aggregates/team.ex index 7af4aa4..8d1ca3b 100644 --- a/lib/reply_express/accounts/aggregates/team.ex +++ b/lib/reply_express/accounts/aggregates/team.ex @@ -3,13 +3,13 @@ defmodule ReplyExpress.Accounts.Aggregates.Team do Team aggregate that handles team-related commands and emits events. """ - alias ReplyExpress.Accounts.Commands.CreateTeam alias ReplyExpress.Accounts.Commands.AddUserToTeam + alias ReplyExpress.Accounts.Commands.CreateTeam alias ReplyExpress.Accounts.Commands.RegisterTeam alias ReplyExpress.Accounts.Commands.RegisterUserToTeam alias ReplyExpress.Accounts.Events.TeamCreated - alias ReplyExpress.Accounts.Events.UserAddedToTeam alias ReplyExpress.Accounts.Events.TeamRegistered + alias ReplyExpress.Accounts.Events.UserAddedToTeam alias ReplyExpress.Accounts.Events.UserRegisteredToTeam @type t :: %__MODULE__{ diff --git a/lib/reply_express/accounts/commands/add_user_to_team.ex b/lib/reply_express/accounts/commands/add_user_to_team.ex index c1bf669..3c0a7d1 100644 --- a/lib/reply_express/accounts/commands/add_user_to_team.ex +++ b/lib/reply_express/accounts/commands/add_user_to_team.ex @@ -6,8 +6,8 @@ defmodule ReplyExpress.Accounts.Commands.AddUserToTeam do use ExConstructor use Vex.Struct - alias ReplyExpress.Accounts.Validators.ValidUserUUID alias ReplyExpress.Accounts.Validators.ValidTeamUUID + alias ReplyExpress.Accounts.Validators.ValidUserUUID @type t :: %__MODULE__{ team_uuid: String.t(), diff --git a/lib/reply_express/accounts/commands/reset_password.ex b/lib/reply_express/accounts/commands/reset_password.ex index 3934403..3e92ed1 100644 --- a/lib/reply_express/accounts/commands/reset_password.ex +++ b/lib/reply_express/accounts/commands/reset_password.ex @@ -8,8 +8,8 @@ defmodule ReplyExpress.Accounts.Commands.ResetPassword do alias ReplyExpress.Accounts.Commands.ResetPassword # alias ReplyExpress.Accounts.Projections.UserToken, as: UserTokenProjection - alias ReplyExpress.Accounts.Validators.ResetPasswordTokenExists alias ReplyExpress.Accounts.UserTokensContext + alias ReplyExpress.Accounts.Validators.ResetPasswordTokenExists @type t :: %__MODULE__{ hashed_password: String.t(), diff --git a/lib/reply_express/accounts/commands/start_user_session.ex b/lib/reply_express/accounts/commands/start_user_session.ex index 9fe3530..2871b3e 100644 --- a/lib/reply_express/accounts/commands/start_user_session.ex +++ b/lib/reply_express/accounts/commands/start_user_session.ex @@ -7,8 +7,8 @@ defmodule ReplyExpress.Accounts.Commands.StartUserSession do use Vex.Struct alias ReplyExpress.Accounts.Commands.StartUserSession - alias ReplyExpress.Accounts.Validators.UniqueSessionToken alias ReplyExpress.Accounts.Validators.LoggedInAtNotExpired + alias ReplyExpress.Accounts.Validators.UniqueSessionToken @type t :: %__MODULE__{ context: String.t(), diff --git a/lib/reply_express/accounts/process_managers/user_registration.ex b/lib/reply_express/accounts/process_managers/user_registration.ex index d89870c..9f33c9e 100644 --- a/lib/reply_express/accounts/process_managers/user_registration.ex +++ b/lib/reply_express/accounts/process_managers/user_registration.ex @@ -15,8 +15,8 @@ defmodule ReplyExpress.Accounts.ProcessManagers.UserRegistration do alias ReplyExpress.Accounts.Commands.RegisterTeam alias ReplyExpress.Accounts.Commands.RegisterUserToTeam alias ReplyExpress.Accounts.Events.TeamRegistered - alias ReplyExpress.Accounts.Events.UserRegisteredToTeam alias ReplyExpress.Accounts.Events.UserRegistered + alias ReplyExpress.Accounts.Events.UserRegisteredToTeam @derive Jason.Encoder @type t :: %__MODULE__{ diff --git a/lib/reply_express_web/controllers/api/v1/fallback_controller.ex b/lib/reply_express_web/controllers/api/v1/fallback_controller.ex index cb1bc86..6883377 100644 --- a/lib/reply_express_web/controllers/api/v1/fallback_controller.ex +++ b/lib/reply_express_web/controllers/api/v1/fallback_controller.ex @@ -2,9 +2,9 @@ defmodule ReplyExpressWeb.API.V1.FallbackController do use Phoenix.Controller alias Ecto.Changeset - alias ReplyExpressWeb.API.V1.ErrorJSON alias ReplyExpressWeb.API.V1.ChangesetJSON alias ReplyExpressWeb.API.V1.CommandValidationErrorJSON + alias ReplyExpressWeb.API.V1.ErrorJSON def call(conn, {:error, :not_found}) do conn diff --git a/mix.exs b/mix.exs index 3b45d30..d252046 100644 --- a/mix.exs +++ b/mix.exs @@ -9,7 +9,7 @@ defmodule ReplyExpress.MixProject do [ app: :reply_express, version: "0.1.0", - elixir: "~> 1.14", + elixir: "~> 1.18", elixirc_paths: elixirc_paths(Mix.env()), start_permanent: Mix.env() == :prod, aliases: aliases(), @@ -86,6 +86,8 @@ defmodule ReplyExpress.MixProject do "reset.test": ["eventstore.reset.test", "ecto.reset.test"], setup: ["deps.get", "ecto.setup"], test: [ + "event_store.create --quiet", + "event_store.init --quiet", "ecto.create --quiet", "ecto.migrate --quiet", "test" diff --git a/test/reply_express/accounts/process_managers/user_registration_test.exs b/test/reply_express/accounts/process_managers/user_registration_test.exs index f5716f2..e2fd5e4 100644 --- a/test/reply_express/accounts/process_managers/user_registration_test.exs +++ b/test/reply_express/accounts/process_managers/user_registration_test.exs @@ -6,8 +6,8 @@ defmodule ReplyExpress.Accounts.ProcessManagers.UserRegistrationTest do alias ReplyExpress.Accounts.Commands.RegisterTeam alias ReplyExpress.Accounts.Commands.RegisterUserToTeam alias ReplyExpress.Accounts.Events.TeamRegistered - alias ReplyExpress.Accounts.Events.UserRegisteredToTeam alias ReplyExpress.Accounts.Events.UserRegistered + alias ReplyExpress.Accounts.Events.UserRegisteredToTeam alias ReplyExpress.Accounts.ProcessManagers.UserRegistration describe "interested?/1" do diff --git a/test/reply_express/accounts/projectors/team_user_projector_test.exs b/test/reply_express/accounts/projectors/team_user_projector_test.exs index 850f600..4a1b7a1 100644 --- a/test/reply_express/accounts/projectors/team_user_projector_test.exs +++ b/test/reply_express/accounts/projectors/team_user_projector_test.exs @@ -6,8 +6,8 @@ defmodule ReplyExpress.Accounts.Projectors.TeamUserProjectorTest do alias ReplyExpress.Accounts.Commands.CreateTeam alias ReplyExpress.Accounts.Commands.CreateUser alias ReplyExpress.Accounts.Events.UserAddedToTeam - alias ReplyExpress.Accounts.Projections.TeamUser alias ReplyExpress.Accounts.Projections.Team, as: TeamProjection + alias ReplyExpress.Accounts.Projections.TeamUser alias ReplyExpress.Accounts.Projections.User, as: UserProjection alias ReplyExpress.Accounts.Projectors.TeamUser, as: TeamUserProjector alias ReplyExpress.Commanded diff --git a/test/reply_express/accounts/user_tokens_context_test.exs b/test/reply_express/accounts/user_tokens_context_test.exs index 29a980b..d5ad548 100644 --- a/test/reply_express/accounts/user_tokens_context_test.exs +++ b/test/reply_express/accounts/user_tokens_context_test.exs @@ -5,8 +5,8 @@ defmodule ReplyExpress.Accounts.UserTokensContextTest do use ReplyExpress.DataCase - alias ReplyExpress.Accounts.Commands.Login alias ReplyExpress.Accounts.Commands.CreateUser + alias ReplyExpress.Accounts.Commands.Login alias ReplyExpress.Accounts.Commands.StartUserSession alias ReplyExpress.Accounts.Projections.User, as: UserProjection alias ReplyExpress.Accounts.Projections.UserToken, as: UserTokenProjection diff --git a/test/reply_express/accounts/users_context_test.exs b/test/reply_express/accounts/users_context_test.exs index 07e8587..39a7ea0 100644 --- a/test/reply_express/accounts/users_context_test.exs +++ b/test/reply_express/accounts/users_context_test.exs @@ -3,8 +3,8 @@ defmodule ReplyExpress.Accounts.UsersContext.Test do use ReplyExpress.DataCase - alias ReplyExpress.Accounts.Commands.GeneratePasswordResetToken alias ReplyExpress.Accounts.Commands.CreateUser + alias ReplyExpress.Accounts.Commands.GeneratePasswordResetToken alias ReplyExpress.Accounts.Commands.ResetPassword alias ReplyExpress.Accounts.Projections.User, as: UserProjection alias ReplyExpress.Accounts.Projections.UserToken, as: UserTokenProjection diff --git a/test/reply_express_web/controllers/api/v1/users/reset_password_controller_test.exs b/test/reply_express_web/controllers/api/v1/users/reset_password_controller_test.exs index 9ff0d59..2dbe723 100644 --- a/test/reply_express_web/controllers/api/v1/users/reset_password_controller_test.exs +++ b/test/reply_express_web/controllers/api/v1/users/reset_password_controller_test.exs @@ -3,8 +3,8 @@ defmodule ReplyExpressWeb.API.V1.Users.ResetPasswordControllerTest do use ReplyExpressWeb.ConnCase - alias ReplyExpress.Accounts.Commands.GeneratePasswordResetToken alias ReplyExpress.Accounts.Commands.CreateUser + alias ReplyExpress.Accounts.Commands.GeneratePasswordResetToken alias ReplyExpress.Accounts.Projections.UserToken, as: UserTokenProjection alias ReplyExpress.Commanded diff --git a/test/support/storage.ex b/test/support/storage.ex index 6ceabe3..f3cda70 100644 --- a/test/support/storage.ex +++ b/test/support/storage.ex @@ -3,6 +3,11 @@ defmodule ReplyExpress.Storage do Provides utilities for resetting the storage state during tests. """ + alias EventStore.Config, as: EventStoreConfig + alias EventStore.Storage.Initializer, as: EventStoreInitializer + alias ReplyExpress.EventStore + alias ReplyExpress.Repo + @doc """ Reset the event store and read store databases. """ @@ -20,15 +25,17 @@ defmodule ReplyExpress.Storage do def reset_eventstore! do {:ok, conn} = - ReplyExpress.EventStore.config() - |> EventStore.Config.default_postgrex_opts() + event_store_config() + |> EventStoreConfig.default_postgrex_opts() |> Postgrex.start_link() - EventStore.Storage.Initializer.reset!(conn, ReplyExpress.EventStore.config()) + EventStoreInitializer.reset!(conn, event_store_config()) end + defp event_store_config, do: EventStore.config() + def reset_readstore! do - config = Application.get_env(:reply_express, ReplyExpress.Repo) + config = Application.get_env(:reply_express, Repo) {:ok, conn} = Postgrex.start_link(config)