defmodule SvelixirNew.MixProject do use Mix.Project # VERSION is the single source of truth; scripts/bump-version.sh writes it and # nothing else. Held as a literal here, the bump hook could not read it: it # parsed `version: "X.Y.Z"` out of mix.exs and this project spells it # `version: @version`, so the read returned nothing and every commit aborted. # # Resolved against __DIR__, never a bare "VERSION". A relative read resolves # against the CURRENT WORKING DIRECTORY, which is this project's root only by # convention — it is not when the root suite shells in from one directory up, # which is exactly how this project is built and tested. @version_path Path.join(__DIR__, "VERSION") @external_resource @version_path @version @version_path |> File.read!() |> String.trim() @source_url "https://github.com/wimwian-org/svelixir_new" @description "Zero-dependency bootstrap archive for Svelixir projects." def project do [ app: :svelixir_new, version: @version, elixir: "~> 1.20", elixirc_paths: elixirc_paths(Mix.env()), deps: deps(), description: @description, package: package(), test_coverage: [tool: ExCoveralls], dialyzer: [plt_add_apps: [:mix]], docs: [main: "readme", extras: ["README.md"]] ] end def cli do [preferred_envs: [coveralls: :test, "coveralls.json": :test]] end # Deliberately empty, so the shipped .app declares exactly # [:kernel, :stdlib, :elixir] — the archive's zero-dependency claim, asserted # by the root suite's archive_test.exs. # # `extra_applications: [:eex]` would be the intuitive addition, because the # generators this task delegates to (`mix new`, `mix phx.new`) render their # templates through EEx. It is not needed and is not harmless: it appends # :eex to `applications` and breaks that assertion. `extra_applications` # governs release inclusion and application start order, NOT code-path # availability — :eex ships with Elixir and its ebin is already on the path # for any in-process `Mix.Task.run/2`. def application, do: [] defp elixirc_paths(:test), do: ["lib", "test/support"] defp elixirc_paths(_), do: ["lib"] # `files` is spelled out only because VERSION is not one of hex's defaults, # and mix.exs reads it at build time — a package without it builds here and # fails to compile for the consumer. Everything else in the list is what the # default would have included anyway. defp package do [ description: @description, licenses: ["MIT"], links: %{"GitHub" => @source_url}, files: ~w(VERSION lib mix.exs README.md .formatter.exs) ] end # RULE: every dep MUST carry an `only:` that EXCLUDES :prod. # # `runtime: false` is NOT the discriminator — {:jason, "~> 1.4", # runtime: false} with no `only:` still emits a full entry in the package's # `requirements`, and this archive's whole point is having none. # # A dep with `only: [:dev, :test]` and the default `runtime: true` also leaks # into the shipped .app's `applications` list while shipping zero BEAMs — # which is why the tooling deps below carry `runtime: false` as well. defp deps do [ {:credo, "~> 1.7", only: [:dev, :test], runtime: false}, {:dialyxir, "~> 1.4", only: [:dev, :test], runtime: false}, {:doctor, "~> 0.21", only: [:dev, :test], runtime: false}, {:ex_doc, "~> 0.34", only: :dev, runtime: false}, {:excoveralls, "~> 0.18", only: :test, runtime: false}, {:ex_machina, "~> 2.8", only: :test, runtime: false}, {:faker, "~> 0.18", only: :test, runtime: false} ] end end