Current section
Files
Jump to
Current section
Files
README.md
# Plumb
A `mix publish` task that releases a package to Hex.
Every check runs before anything is written. A run that fails verification leaves
the repository unchanged.
```bash
mix publish patch # 0.1.1 -> 0.1.2
mix publish minor # 0.1.1 -> 0.2.0
mix publish major # 0.1.1 -> 1.0.0
mix publish 0.4.0-rc.1 # an explicit version, which must sort above the current one
mix publish current # upload the version already in mix.exs
```
## Installation
```elixir
def deps do
[
{:plumb, "~> 0.2", only: :dev, runtime: false}
]
end
```
## Sequence
Checks, in order. Nothing is written until all of them pass:
1. The git working tree is clean.
2. The target tag does not exist locally.
3. The target tag does not exist on the remote.
4. The README install snippet fits the version being released. Off by default; see
[The README check](#the-readme-check).
5. `mix format --check-formatted`.
6. `mix test`.
7. `mix docs` builds.
8. `mix hex.build` produces a valid package.
Then confirmation is asked, and on `y`:
9. `mix.exs` is rewritten with the new version.
10. It is committed as `Release vX.Y.Z`.
11. An annotated tag `vX.Y.Z` is created.
12. `HEAD` and the tag are pushed.
13. `mix hex.publish` uploads the package and its documentation.
The tag is pushed before the upload, so `source_ref` in the published
documentation resolves as soon as the docs are live.
## `mix publish current`
Uploads the version already in `mix.exs`. Nothing is bumped, committed or tagged.
Requires the tag for that version to exist locally, to be on the remote, to point
at the same commit in both, and `HEAD` to be on it. The tarball is built from the
working tree, so a `HEAD` ahead of the tag would upload code the tag does not
point at, and is refused.
## The README check
Compares the requirement the README names for this package against the version
being released — not the version in `mix.exs` — so it fails before the bump.
Off unless configured:
```elixir
def project do
[
plumb: [readme: :exact]
]
end
```
- `:satisfies` — the version being released must satisfy the requirement the
README names.
- `:exact` — the README must name `~> MAJOR.MINOR` of the version being released.
- `false` — the default.
- `:readme_path` — defaults to `"README.md"`.
The requirement is read from the first `{:app_name, "requirement"}` in the file. A
README that names no dependency on the package fails the check.
## Where the version comes from
A `@version "..."` module attribute, when there is one:
```elixir
@version "0.3.0"
def project do
[version: @version, docs: [source_ref: "v#{@version}"]]
end
```
Otherwise a literal `version: "0.3.0"` in the project config. Only the first
occurrence is rewritten, and only when the version is a literal string — a
`version: @version` is left alone so the attribute is what gets bumped.
A `mix.exs` with neither is refused.
## Options
- `--dry-run` — run every check and build the tarball, report what would follow,
write nothing
- `--remote NAME` — the git remote to push to, default `origin`
- `--allow-untracked` — untracked files pass the clean-tree check. Tracked changes
still block it; untracked files are never committed
- `--skip CHECKS` — comma-separated checks to omit: `readme`, `format`, `test`,
`docs`, `build`
- `--yes` — skip the confirmation prompt
```bash
mix publish minor --dry-run
mix publish patch --remote upstream
mix publish patch --skip docs
```
## Scope
Changelog entries are not generated. [`expublish`](https://hex.pm/packages/expublish)
covers similar ground and does generate them.
## License
MIT