Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
6dc4389
Bump elixir version in asdf config
zoldar Jun 8, 2026
39c0bd2
Remove unused module requires
zoldar Jun 8, 2026
188f3dc
Avoid generating function body inside `defprotocol`
zoldar Jun 8, 2026
b87a49b
unused require fixup
zoldar Jun 8, 2026
4c87846
Don't branch on always-true expression
zoldar Jun 8, 2026
12d90c2
Fix usages of :erlang.phash2 dialyzer trick
zoldar Jun 8, 2026
a9bf2d7
Don't check for expression which is always true
zoldar Jun 8, 2026
d727b56
Fix faulty `repo.config` -> `repo.config()`
zoldar Jun 8, 2026
e6d9e79
Avoid using `Phoenix.Component` twice
zoldar Jun 8, 2026
26ed90f
Bump ExMoney
zoldar Jun 8, 2026
934ab14
Add `logger_backends` dependency
zoldar Jun 8, 2026
d0952a1
Use `LoggerBackends.add` instead of `Logger.add_backend`
zoldar Jun 8, 2026
3ba70ed
Remove test assertions already caught by type checker
zoldar Jun 8, 2026
c842b0d
Don't pattern match on regex
zoldar Jun 8, 2026
3e7b597
Avoid passing literal for subscription in `Status.in?` test calls
zoldar Jun 8, 2026
b994b35
Fix a type issue in `Audit.Encoder` reported by dialyzer
zoldar Jun 9, 2026
af155ce
Fix `phash2` workaround in `Plausible`
zoldar Jun 9, 2026
3236999
Bump OTP to 29.0.1 in asdf config
zoldar Jun 9, 2026
aef4db1
Bump patch versions of `x509` and `credo` dependencies
zoldar Jun 9, 2026
e375f48
Remove `Bamboo.SMTPAdapter` as it's no longer maintained and broken o…
zoldar Jun 9, 2026
3b2763c
Make user agent test string larger to trigger ua timeout telemetry event
zoldar Jun 9, 2026
ad2677f
Fix regex comparison as internal reference is changing now
zoldar Jun 9, 2026
8e35ef4
Add FIXME comments for surfaced cache bugs
zoldar Jun 9, 2026
830bc41
Downgrade OTP to more proven 28.5.0.1
zoldar Jun 9, 2026
5072ab0
Use exported regex pattern for stored regex to avoid cache issues
zoldar Jun 9, 2026
cf38649
Bump elixir in asdf to 1.20.1
zoldar Jun 10, 2026
369ca46
Add dialyzer-ignore file to suppress Ecto.Multi opaque errors
zoldar Jun 10, 2026
a90a948
Update builder image in Dockerfile
zoldar Jun 10, 2026
edb8b45
Bust CI cache
zoldar Jun 10, 2026
10d23e2
Fix type errors in CE
zoldar Jun 10, 2026
df5a991
Make user agent test string even longer to increase chances of timeout
zoldar Jun 10, 2026
7d904dd
Address credo issues in touched files
zoldar Jun 10, 2026
7ce3bd3
Fix another dialyzer regression
zoldar Jun 10, 2026
a183067
Increase credo's max nesting threshold from 2 to 3 because this is bs
zoldar Jun 10, 2026
fec2b16
Allow operators in if condition assignment expressions in credo
zoldar Jun 10, 2026
767c7e1
Ignore a bogus dialyzer error
zoldar Jun 10, 2026
215bafd
Re-add missing Logger require
zoldar Jun 10, 2026
01dc672
Add changelog entry
zoldar Jun 10, 2026
8c9b47d
Apply suggestions from code review
zoldar Jul 7, 2026
49ddfbc
Bump elixir to 1.20.2 and OTP to 28.5.0.3
zoldar Jul 7, 2026
9f2d283
Update packages according to security advisories from mix deps.get
zoldar Jul 7, 2026
58e057a
Update code and tests to account for changed Finch error format
zoldar Jul 7, 2026
6f4769d
Stub DNS lookup in live domain change tests instead of expecting a si…
zoldar Jul 7, 2026
a05418d
Avoid logging error in live tests due to premature close of DB conn
zoldar Jul 7, 2026
0441b0b
Remove skipped empty test
zoldar Jul 7, 2026
6728097
Remove TODO and adjust typespec for readability at least
zoldar Jul 7, 2026
8175c8c
Make credo happy about missing moduledocs for internal stuff
zoldar Jul 7, 2026
bb9f7b7
Bump phoenix in response to recent security advisory
zoldar Jul 7, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions .credo.exs
Original file line number Diff line number Diff line change
Expand Up @@ -119,16 +119,15 @@
{Credo.Check.Refactor.CyclomaticComplexity, false},
{Credo.Check.Refactor.FilterCount, []},
{Credo.Check.Refactor.FilterFilter, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.MatchInCondition, [allow_operators: true]},
{Credo.Check.Refactor.RedundantWithClauseResult, []},
{Credo.Check.Refactor.RejectReject, []},
{Credo.Check.Refactor.FunctionArity, []},
{Credo.Check.Refactor.LongQuoteBlocks, []},
{Credo.Check.Refactor.MatchInCondition, []},
{Credo.Check.Refactor.MapJoin, []},
{Credo.Check.Refactor.NegatedConditionsInUnless, []},
{Credo.Check.Refactor.NegatedConditionsWithElse, false},
{Credo.Check.Refactor.Nesting, []},
{Credo.Check.Refactor.Nesting, [max_nesting: 3]},
{Credo.Check.Refactor.UnlessWithElse, []},
{Credo.Check.Refactor.WithClauses, []},
{Credo.Check.Refactor.FilterFilter, []},
Expand Down
6 changes: 6 additions & 0 deletions .dialyzer_ignore.exs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
[
{"lib/plausible/goals/goals.ex", :call_without_opaque},
{"lib/plausible/sites.ex", :call_without_opaque},
{"lib/plausible/teams/invitations.ex", :call_without_opaque},
{"lib/plausible_web/live/components/modal.ex", :pattern_match, 1}
]
2 changes: 1 addition & 1 deletion .github/workflows/elixir.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ concurrency:
cancel-in-progress: true

env:
CACHE_VERSION: v17
CACHE_VERSION: v18
PERSISTENT_CACHE_DIR: cached

jobs:
Expand Down
4 changes: 2 additions & 2 deletions .tool-versions
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
erlang 27.3.4.6
elixir 1.19.4-otp-27
erlang 28.5.0.3
elixir 1.20.2-otp-28
nodejs 23.2.0
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ All notable changes to this project will be documented in this file.
### Removed

- Removed the standalone team switcher page; team switching is now done from the topbar dropdown only
- Removed `Bamboo.SMTPAdapter` from supported e-mail adapters; the library is no longer in active developments and does not compile under Elixir 1.20+

### Changed

Expand Down
5 changes: 2 additions & 3 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# we can not use the pre-built tar because the distribution is
# platform specific, it makes sense to build it in the docker

ARG ALPINE_VERSION=3.22.2

#### Builder
FROM hexpm/elixir:1.19.4-erlang-27.3.4.6-alpine-${ALPINE_VERSION} AS buildcontainer
FROM hexpm/elixir:1.20.2-erlang-28.5.0.3-alpine-3.22.5@sha256:8875407828c1b789485f9fcc6006e1ace39bb073b0467a95df3a3905d8d86d30 AS buildcontainer

ARG MIX_ENV=ce

Expand Down Expand Up @@ -55,7 +54,7 @@ COPY rel rel
RUN mix release plausible

# Main Docker Image
FROM alpine:${ALPINE_VERSION}
FROM alpine:3.22.5@sha256:14358309a308569c32bdc37e2e0e9694be33a9d99e68afb0f5ff33cc1f695dce
LABEL maintainer="plausible.io <hello@plausible.io>"

ARG BUILD_METADATA={}
Expand Down
14 changes: 0 additions & 14 deletions config/runtime.exs
Original file line number Diff line number Diff line change
Expand Up @@ -742,20 +742,6 @@ case mailer_adapter do
hackney_opts: [recv_timeout: :timer.seconds(10)],
api_key: get_var_from_path_or_env(config_dir, "SENDGRID_API_KEY")

"Bamboo.SMTPAdapter" ->
config :plausible, Plausible.Mailer,
adapter: Bamboo.SMTPAdapter,
server: get_var_from_path_or_env(config_dir, "SMTP_HOST_ADDR", "mail"),
hostname: base_url.host,
port: get_var_from_path_or_env(config_dir, "SMTP_HOST_PORT", "25"),
username: get_var_from_path_or_env(config_dir, "SMTP_USER_NAME"),
password: get_var_from_path_or_env(config_dir, "SMTP_USER_PWD"),
tls: :if_available,
allowed_tls_versions: [:tlsv1, :"tlsv1.1", :"tlsv1.2"],
ssl: get_bool_from_path_or_env(config_dir, "SMTP_HOST_SSL_ENABLED", false),
retries: get_var_from_path_or_env(config_dir, "SMTP_RETRIES") || 2,
no_mx_lookups: get_bool_from_path_or_env(config_dir, "SMTP_MX_LOOKUPS_ENABLED", true)

"Bamboo.Mua" ->
config :plausible, Plausible.Mailer, adapter: Bamboo.Mua

Expand Down
4 changes: 2 additions & 2 deletions extra/lib/license.ex
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,9 @@ defmodule Plausible.License do
at hello@plausible.io to discuss obtaining a license.
"""

require Logger

if Mix.env() == :prod do
require Logger

def ensure_valid_license do
if has_valid_license?() do
:ok
Expand Down
19 changes: 12 additions & 7 deletions extra/lib/plausible/audit/encoder.ex
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,13 @@ defmodule Plausible.Audit.EncoderError do
end

defprotocol Plausible.Audit.Encoder do
def encode(x, opts \\ [])
def encode(x)

def encode(x, opts)
end

defimpl Plausible.Audit.Encoder, for: Ecto.Changeset do
def encode(changeset, opts) do
def encode(changeset, opts \\ []) do
changes =
Enum.reduce(changeset.changes, %{}, fn {k, v}, acc ->
Map.put(acc, k, Plausible.Audit.Encoder.encode(v, opts))
Expand All @@ -32,7 +34,7 @@ defimpl Plausible.Audit.Encoder, for: Ecto.Changeset do
end

defimpl Plausible.Audit.Encoder, for: Map do
def encode(x, opts) do
def encode(x, opts \\ []) do
{allow_not_loaded, data} = Map.pop(x, :__allow_not_loaded__)
raise_on_not_loaded? = Keyword.get(opts, :raise_on_not_loaded?, true)

Expand All @@ -53,22 +55,24 @@ defimpl Plausible.Audit.Encoder, for: Map do
end

defimpl Plausible.Audit.Encoder, for: [Integer, BitString, Float] do
def encode(x, _opts), do: x
def encode(x, _opts \\ []), do: x
end

defimpl Plausible.Audit.Encoder, for: [DateTime, Date, NaiveDateTime, Time] do
def encode(x, _opts), do: to_string(x)
def encode(x, _opts \\ []), do: to_string(x)
end

defimpl Plausible.Audit.Encoder, for: Atom do
def encode(x, opts \\ [])

def encode(nil, _opts), do: nil
def encode(true, _opts), do: true
def encode(false, _opts), do: false
def encode(x, _opts), do: Atom.to_string(x)
end

defimpl Plausible.Audit.Encoder, for: List do
def encode(x, opts) do
def encode(x, opts \\ []) do
Enum.map(x, &Plausible.Audit.Encoder.encode(&1, opts))
end
end
Expand Down Expand Up @@ -116,12 +120,13 @@ defimpl Plausible.Audit.Encoder, for: Any do

quote do
defimpl Plausible.Audit.Encoder, for: unquote(module) do
def encode(struct, opts) do
def encode(struct, opts \\ []) do
Plausible.Audit.Encoder.encode(unquote(extractor), opts)
end
end
end
end

def encode(_), do: raise("Implement me")
def encode(_, _), do: raise("Implement me")
end
1 change: 0 additions & 1 deletion extra/lib/plausible/auth/sso/domain/verification.ex
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ defmodule Plausible.Auth.SSO.Domain.Verification do
"""

alias Plausible.Auth.SSO.Domain
require Domain

@prefix "plausible-sso-verification"

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ defmodule Plausible.InstallationSupport.Detection.Diagnostics do
@moduledoc """
Module responsible for translating diagnostics to user-friendly errors and recommendations.
"""
require Logger

# in this struct, nil means indeterminate
defstruct v1_detected: nil,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ defmodule Plausible.InstallationSupport.Verification.Diagnostics do
@moduledoc """
Module responsible for translating diagnostics to user-friendly errors and recommendations.
"""
require Logger

# In this struct
# - the default nil value for each field means that the value is indeterminate (e.g. we didn't even get to the part where response_status is set)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,6 @@ defmodule PlausibleWeb.CustomerSupport.Team.Components.Billing do
import Ecto.Query, only: [from: 2]
import PlausibleWeb.Components.Generic

require Plausible.Billing.Subscription.Status

def update(%{team: team}, socket) do
usage = Teams.Billing.quota_usage(team, with_features: true)

Expand Down
4 changes: 3 additions & 1 deletion lib/mix/tasks/create_free_subscription.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
defmodule Mix.Tasks.CreateFreeSubscription do
@moduledoc false

use Mix.Task
use Plausible.Repo
require Logger

alias Plausible.Billing.Subscription

# coveralls-ignore-start
Expand Down
3 changes: 2 additions & 1 deletion lib/mix/tasks/generate_referrer_favicons.ex
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
defmodule Mix.Tasks.GenerateReferrerFavicons do
@moduledoc false

use Mix.Task
use Plausible.Repo
require Logger

@dialyzer {:nowarn_function, run: 1}
# coveralls-ignore-start
Expand Down
1 change: 0 additions & 1 deletion lib/mix/tasks/send_pageview.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ defmodule Mix.Tasks.SendPageview do
"""

use Mix.Task
require Logger

@default_host "http://localhost:8000"
@default_ip_address "127.0.0.1"
Expand Down
8 changes: 7 additions & 1 deletion lib/plausible.ex
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,13 @@ defmodule Plausible do

defmacro always(term) do
quote do
:erlang.phash2(1, 1) == 0 && unquote(term)
case :erlang.phash2(1, 1) do
0 ->
unquote(term)

1 ->
not unquote(term)
end
end
end

Expand Down
4 changes: 1 addition & 3 deletions lib/plausible/application.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@ defmodule Plausible.Application do
use Application
use Plausible

require Logger

def start(_type, _args) do
on_ee(do: Plausible.License.ensure_valid_license())
on_ce(do: :inet_db.set_tcp_module(:happy_tcp))
Expand Down Expand Up @@ -360,7 +358,7 @@ defmodule Plausible.Application do
end

def setup_sentry() do
Logger.add_backend(Sentry.LoggerBackend)
LoggerBackends.add(Sentry.LoggerBackend)

:telemetry.attach_many(
"oban-errors",
Expand Down
2 changes: 1 addition & 1 deletion lib/plausible/billing/billing.ex
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ defmodule Plausible.Billing do
"""
use Plausible
use Plausible.Repo
require Plausible.Billing.Subscription.Status

alias Plausible.Auth
alias Plausible.Billing.Subscription
alias Plausible.Teams
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,6 @@ defmodule Plausible.DataMigration.PopulateEventSessionColumns do
"""
use Plausible.DataMigration, dir: "PopulateEventSessionColumns", repo: Plausible.IngestRepo

require Logger

# See https://clickhouse.com/docs/en/sql-reference/dictionaries#cache for meaning of these defaults
@default_dictionary_config %{
lifetime: 600_000,
Expand Down
2 changes: 1 addition & 1 deletion lib/plausible/ecto/types/compiled_regex.ex
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,6 @@ defmodule Plausible.Ecto.Types.CompiledRegex do
def cast(val) when is_binary(val), do: {:ok, val}
def cast(_), do: :error

def load(val), do: {:ok, Regex.compile!(val)}
def load(val), do: {:ok, Regex.compile!(val, "E")}
def dump(val), do: {:ok, val}
end
2 changes: 1 addition & 1 deletion lib/plausible/exports.ex
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,7 @@ defmodule Plausible.Exports do
{:error, {:http_error, 404, _response}} ->
nil

{:error, %Mint.TransportError{} = e} ->
{:error, %Finch.TransportError{} = e} ->
raise e
end
end
Expand Down
2 changes: 0 additions & 2 deletions lib/plausible/google/api.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ defmodule Plausible.Google.API do
alias Plausible.Google.SearchConsole
alias Plausible.Stats.Query

require Logger

@search_console_scope URI.encode_www_form(
"email https://www.googleapis.com/auth/webmasters.readonly"
)
Expand Down
12 changes: 8 additions & 4 deletions lib/plausible/http_client.ex
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
defmodule Plausible.HTTPClient.Non200Error do
@moduledoc false

defstruct reason: nil

@type t :: %__MODULE__{reason: Finch.Response.t()}
Expand All @@ -11,13 +13,17 @@ defmodule Plausible.HTTPClient.Non200Error do
end

defmodule Plausible.HTTPClient.Interface do
@moduledoc false

@type t() :: module()

@type finch_request_opts() :: Keyword.t()
@type url() :: Finch.Request.url()
@type headers() :: Finch.Request.headers()
@type params() :: Finch.Request.body() | map()
@type response() ::
{:ok, Finch.Response.t()}
| {:error, Mint.Types.error() | Finch.Error.t() | Plausible.HTTPClient.Non200Error.t()}
| {:error, Finch.error() | Plausible.HTTPClient.Non200Error.t()}

@callback get(url(), headers(), params()) :: response()
@callback get(url(), headers()) :: response()
Expand Down Expand Up @@ -58,9 +64,7 @@ defmodule Plausible.HTTPClient do
call(:get, url, headers, params)
end

# TODO: Is it possible to tell the type checker that we're returning a module that conforms to the
# Plausible.HTTPClient.Interface behaviour?
@spec impl() :: Plausible.HTTPClient
@spec impl() :: Plausible.HTTPClient.Interface.t()
def impl() do
Application.get_env(:plausible, :http_impl, __MODULE__)
end
Expand Down
2 changes: 0 additions & 2 deletions lib/plausible/ingestion/counters.ex
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ defmodule Plausible.Ingestion.Counters do

@behaviour :gen_cycle

require Logger

alias Plausible.Ingestion.Counters.Buffer
alias Plausible.Ingestion.Counters.Record
alias Plausible.Ingestion.Counters.TelemetryHandler
Expand Down
2 changes: 0 additions & 2 deletions lib/plausible/ingestion/persistor/embedded.ex
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ defmodule Plausible.Ingestion.Persistor.Embedded do

alias Plausible.ClickhouseEventV2

require Logger

def persist_event(ingest_event, previous_user_id, opts) do
event = ingest_event.clickhouse_event
session_attrs = ingest_event.clickhouse_session_attrs
Expand Down
4 changes: 2 additions & 2 deletions lib/plausible/open_telemetry.ex
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
defmodule Plausible.OpenTelemetry do
@moduledoc false

require OpenTelemetry.Tracer, as: Tracer
alias OpenTelemetry.Tracer

def current_trace_id do
case OpenTelemetry.Tracer.current_span_ctx() do
case Tracer.current_span_ctx() do
:undefined ->
nil

Expand Down
2 changes: 0 additions & 2 deletions lib/plausible/open_telemetry/logger.ex
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@ defmodule Plausible.OpenTelemetry.Logger do
to the Logger metadata when Phoenix router dispatch starts.
"""

require Logger

@doc """
Attaches telemetry handlers to set trace_id in Logger metadata.
Expand Down
5 changes: 4 additions & 1 deletion lib/plausible/session/cache_store.ex
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
defmodule Plausible.Session.CacheStore do
require Logger
@moduledoc """
Session management on the basis of incoming events.
"""

alias Plausible.Session.WriteBuffer

@lock_timeout 1000
Expand Down
Loading
Loading