From 07137a1eddebeb2c40c03da653cf7349c080b7f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 17 Aug 2024 22:02:08 +0200 Subject: [PATCH] Improve docs around only and optional, closes #13782 --- .../pages/references/library-guidelines.md | 8 ++++--- lib/mix/lib/mix/tasks/deps.ex | 24 +++++++++++++++---- 2 files changed, 24 insertions(+), 8 deletions(-) diff --git a/lib/elixir/pages/references/library-guidelines.md b/lib/elixir/pages/references/library-guidelines.md index b8e82d7d2da..c669d3793e3 100644 --- a/lib/elixir/pages/references/library-guidelines.md +++ b/lib/elixir/pages/references/library-guidelines.md @@ -35,8 +35,10 @@ Projects are often made available to other developers [by publishing a Hex packa ## Dependency handling -When your library is published and used as a dependency, its [lockfile](https://hexdocs.pm/mix/Mix.Project.html#module-configuration) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI). +When your library is used as a dependency, it runs by default in the `:prod` environment. Therefore, if your library has dependencies that are only useful in development or testing, you want to specify those dependencies with the `:only` option. You can also specify `:optional` dependencies in your library, which are not enforced upon users of your library. In such cases, you should also consider compiling your projects with the `mix compile --no-optional-deps --warnings-as-errors` in your test environments, to ensure your library compiles without warnings even if optional dependencies are missing. See `mix deps` for all available options. -On the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS). +Keep in mind your library's [lockfile](`Mix.Project#module-configuration`) (usually named `mix.lock`) is _ignored by the host project_. Running `mix deps.get` in the host project attempts to get the latest possible versions of your library’s dependencies, as specified by the requirements in the `deps` section of your `mix.exs`. These versions might be greater than those stored in your `mix.lock` (and hence used in your tests / CI). -The best practice of handling `mix.lock` file therefore would be to keep it in VCS, and run two different Continuous Integration (CI) workflows: the usual deterministic one, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates. +On the other hand, contributors of your library, need a deterministic build, which implies the presence of `mix.lock` in your Version Control System (VCS), such as `git`. + +If you want to validate both scenarios, you should check the `mix.lock` into version control and run two different Continuous Integration (CI) workflows: one that relies on the `mix.lock` for deterministic builds, and another one, that starts with `mix deps.unlock --all` and always compiles your library and runs tests against latest versions of dependencies. The latter one might be even run nightly or otherwise recurrently to stay notified about any possible issue in regard to dependencies updates. diff --git a/lib/mix/lib/mix/tasks/deps.ex b/lib/mix/lib/mix/tasks/deps.ex index d6f0b874046..8fe0572c56c 100644 --- a/lib/mix/lib/mix/tasks/deps.ex +++ b/lib/mix/lib/mix/tasks/deps.ex @@ -62,9 +62,10 @@ defmodule Mix.Tasks.Deps do * `:app` - when set to `false`, does not read the app file for this dependency. By default, the app file is read - * `:env` - the environment (as an atom) to run the dependency on; defaults to `:prod`. - This is not necessary for dependencies on other apps within the same umbrella project, - see the `:in_umbrella` option below. + * `:env` - the environment (as an atom) to run the dependency on. + While your current project runs in `:dev` by default, dependencies + defaults to `:prod` (except for `:in_umbrella` dependencies, see + below) * `:compile` - a command (string) to compile the dependency; defaults to a `mix`, `rebar` or `make` command @@ -75,13 +76,18 @@ defmodule Mix.Tasks.Deps do use the optional dependency. However, if the other project includes the optional dependency on its own, the requirements and options specified here will also be applied. Optional dependencies will _not_ - be started by the application. + be started by the application. You should consider compiling your + projects with the `mix compile --no-optional-deps --warnings-as-errors` + during test, to ensure your project compiles without warnings even + if optional dependencies are missing * `:only` - the dependency is made available only in the given environments, useful when declaring dev- or test-only dependencies; by default the dependency will be available in all environments. The value of this option can either be a single environment (like `:dev`) or a list of environments - (like `[:dev, :test]`) + (like `[:dev, :test]`). Keep in mind that your project runs in the `:dev` + environment by default, however, all of your dependencies run in the `:prod` + environment (unless the `:env` option above is given) * `:targets` - the dependency is made available only for the given targets. By default the dependency will be available in all targets. The value @@ -109,6 +115,14 @@ defmodule Mix.Tasks.Deps do * `:system_env` - an enumerable of key-value tuples of binaries to be set as environment variables when loading or compiling the dependency + When a project is used as a dependency, it runs by default in the `:prod` + environment. Therefore, if your project has dependencies that are only + useful in development or testing, you want to specify those dependencies with + the `:only` option above. You can also specify `:optional` dependencies + in your project, which are not enforced upon users of your library, as outlined + above. Finally, the [lockfile](`Mix.Project#module-configuration`) (usually + named `mix.lock`) is ignored when a project is used as a dependency. + ### Git options (`:git`) * `:git` - the Git repository URI