Skip to content

Commit

Permalink
Improve docs around only and optional, closes #13782
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Aug 17, 2024
1 parent b8cec30 commit 07137a1
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 8 deletions.
8 changes: 5 additions & 3 deletions lib/elixir/pages/references/library-guidelines.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
24 changes: 19 additions & 5 deletions lib/mix/lib/mix/tasks/deps.ex
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 07137a1

Please sign in to comment.