Skip to content

Commit f93566f

Browse files
authored
Merge pull request #33 from ausimian/issue/24-castle-task-namespace
refactor!: rename mix forecastle.relup to mix castle.relup
2 parents 35b8a24 + 6f56af0 commit f93566f

10 files changed

Lines changed: 56 additions & 35 deletions

File tree

AGENTS.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -664,7 +664,7 @@ around it composes instead:
664664

665665
## Relup generation and upgrade strategy
666666

667-
`mix forecastle.relup` takes an upgrade strategy — `auto` by default, `--hot`,
667+
`mix castle.relup` takes an upgrade strategy — `auto` by default, `--hot`,
668668
or `--restart` — and it is a property of each transition in the relup rather
669669
than of the release, because that is what it is: a relup for release X carries
670670
one entry per from-version, and whether that particular edge can be hot has
@@ -886,7 +886,7 @@ changing the fixture.
886886
| --- | --- |
887887
| `lib/forecastle.ex` | Release step hooks (the whole of the build-time logic) |
888888
| `lib/mix/tasks/compile/appup.ex` | `:appup` compiler — evaluates the file named by the `:appup` project key and writes `<app>.appup` into `ebin` |
889-
| `lib/mix/tasks/forecastle.relup.ex` | `mix forecastle.relup` — chooses an upgrade strategy per transition, and writes the relup |
889+
| `lib/mix/tasks/castle.relup.ex` | `mix castle.relup` — chooses an upgrade strategy per transition, and writes the relup |
890890
| `priv/castle.sh.eex` | EEx template for `bin/castle`, the release management CLI |
891891
| `priv/env.sh.eex` | EEx template for the fragment appended to the release's `env.sh` |
892892
| `priv/start.sh.eex` | EEx template for `bin/start`, the inert program heart is handed |
@@ -923,7 +923,7 @@ directory to start from a clean slate.
923923
| `test/forecastle/castle_cli_test.exs` | `bin/castle` as a shell script, against a launcher stub that records its arguments |
924924
| `test/forecastle/env_script_test.exs` | The `env.sh` fragment as a shell script, sourced in a release-shaped directory with a launcher stub: the heart environment it leaves behind, and which provisional version each state of the two markers selects |
925925
| `test/forecastle/configuration_test.exs` | A release that names its own runtime configuration file and declares providers whose init arguments are not keyword lists — assembled, and booted through `bin/<name> eval` |
926-
| `test/forecastle/relup_test.exs` | `mix forecastle.relup` as a command, against three assembled releases: argument handling, exit status, and all three upgrade strategies |
926+
| `test/forecastle/relup_test.exs` | `mix castle.relup` as a command, against three assembled releases: argument handling, exit status, and all three upgrade strategies |
927927
| `test/forecastle/upgrade_test.exs` | Booting a release and hot-upgrading it, including the code path of an application the relup does not load, tagged `:e2e` |
928928
| `test/forecastle/restart_upgrade_test.exs` | The same shape through an emulator restart: the OS pid changes, an uncommitted release rolls back when killed, and a commit makes it what an ordinary start boots. Tagged `:e2e` |
929929

README.md

Lines changed: 12 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,10 @@ upgrades. This includes:
1010
- Adding a `bin/castle` command for unpacking and installing releases, alongside
1111
the standard Mix launcher.
1212

13-
Additionally, `Forecastle` ships with a appup compiler and a mix task for relup generation.
13+
Additionally, `Forecastle` ships with an appup compiler and a mix task for relup
14+
generation. Both are named for `Castle` rather than for the package that
15+
implements them - `mix castle.relup` and the `:appup` compiler - because where the
16+
build-time code lives is a packaging decision, and what a developer types is not.
1417

1518
## Installation
1619

@@ -223,7 +226,7 @@ on, with nobody intervening. `bin/<release> version` reports that version too,
223226
because what it prints is the version *to be booted*; ask the running system if
224227
you want to know what is running.
225228

226-
**Only the one-stage `restart_emulator` is supported.** `mix forecastle.relup`
229+
**Only the one-stage `restart_emulator` is supported.** `mix castle.relup`
227230
never generates the two-stage `restart_new_emulator` and refuses it wherever it
228231
finds one; see below.
229232

@@ -277,12 +280,12 @@ build wrote stays where it is.
277280

278281
## Relup Generation
279282

280-
Forecastle contains a mix task, `forecastle.relup`, that simplifies the generation of
281-
the relup file. Assuming you have two _unpacked_ releases e.g. `0.1.0` and `0.1.1`
282-
and you wish to generate a relup between them:
283+
`Forecastle` provides the mix task `castle.relup`, which simplifies the generation
284+
of the relup file. Assuming you have two _unpacked_ releases e.g. `0.1.0` and
285+
`0.1.1` and you wish to generate a relup between them:
283286

284287
```shell
285-
> mix forecastle.relup --target myapp/releases/0.1.1/myapp --fromto myapp/releases/0.1.0/myapp
288+
> mix castle.relup --target myapp/releases/0.1.1/myapp --fromto myapp/releases/0.1.0/myapp
286289
```
287290

288291
If the generated file is in the project root, it will be copied during
@@ -314,13 +317,13 @@ not of either release, so it is chosen per relup:
314317

315318
```shell
316319
# auto: hot where it can be
317-
> mix forecastle.relup --target ... --fromto ...
320+
> mix castle.relup --target ... --fromto ...
318321

319322
# require a hot upgrade, and fail rather than degrade
320-
> mix forecastle.relup --target ... --fromto ... --hot
323+
> mix castle.relup --target ... --fromto ... --hot
321324

322325
# force a full emulator restart, with no appups at all
323-
> mix forecastle.relup --target ... --fromto ... --restart
326+
> mix castle.relup --target ... --fromto ... --restart
324327
```
325328

326329
`--hot` and `--restart` are mutually exclusive, and each may be given once.

RELEASE.md

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@
104104
a launcher stub as well. A continuation that fails and rolls back on the way up
105105
belongs to `restart_new_emulator`, which is not supported; see *Known
106106
limitations*.
107-
- `mix forecastle.relup` now takes an upgrade strategy, because whether a
107+
- `mix castle.relup` now takes an upgrade strategy, because whether a
108108
transition can be hot is a property of the edge between two releases rather
109109
than of either release. `--hot` requires a genuine hot upgrade and fails,
110110
having written nothing, if the transition cannot be one - a missing appup
@@ -329,6 +329,19 @@
329329

330330
### Changed
331331

332+
- **Breaking:** `mix forecastle.relup` is now `mix castle.relup`. The task is
333+
still implemented in Forecastle and still ships with it; only the name has
334+
changed. Where build-time code lives is a packaging decision and what the task
335+
is called is a user-interface one, and making the two agree split the
336+
vocabulary in half: an operator ran `bin/castle install` while a developer ran
337+
`mix forecastle.relup`, against a package that is, by design, in nobody's
338+
`mix.exs`. Both READMEs say to depend on `Castle`, so `castle.*` is the name
339+
the user already thinks in. There is no compatibility alias — a shim for a
340+
package documented as not taken directly is code maintained forever for a user
341+
who does not exist — so rename the invocation in any build pipeline that calls
342+
it. `mix compile.appup` is unaffected: it is named by its `:compilers` entry
343+
rather than by a package.
344+
([forecastle#24](https://github.com/ausimian/forecastle/issues/24))
332345
- **Breaking:** Forecastle no longer touches configuration. It used to set
333346
`:runtime_config_path` to `false`, install a `Config.Reader` of its own,
334347
initialise every config provider itself and stash the results, and rename the
@@ -439,7 +452,7 @@
439452
- The Castle integration is installed by extending the release's `env.sh`
440453
rather than by replacing the launcher. An `env.sh` supplied through
441454
`rel/env.sh.eex` is preserved and runs first.
442-
- `mix forecastle.relup` with no strategy switch is now `auto`, which changes what
455+
- `mix castle.relup` with no strategy switch is now `auto`, which changes what
443456
an existing invocation does with some transitions. Case by case, against a task
444457
that simply asked `systools` for the relup:
445458

@@ -476,7 +489,7 @@
476489
refuses an appup-supplied emulator restart that the old task packaged. What it
477490
is good for is a pipeline that wants the generation to fail rather than degrade.
478491
`--restart` is the way to get a relup out of the two changed cases.
479-
- A `mix forecastle.relup` run that fails now writes nothing at all. It used to
492+
- A `mix castle.relup` run that fails now writes nothing at all. It used to
480493
let `systools` write the relup and report afterwards, which was harmless while
481494
every refusal came from `systools` itself; the strategies add refusals that can
482495
only be made once a relup has been generated, so the file is now written by the
@@ -493,7 +506,7 @@
493506
relup empty or half a plan even though the run failed. A reader now sees the
494507
whole of one relup or the whole of the other, and a build that reads it while a
495508
generation is running cannot read a partial one.
496-
- `mix forecastle.relup` now requires at least one of `--fromto`, `--upfrom` or
509+
- `mix castle.relup` now requires at least one of `--fromto`, `--upfrom` or
497510
`--downto`. It used to accept none and write a relup with no transitions in it,
498511
which is not an upgrade plan and which `release_handler` can do nothing with.
499512
- Raised the minimum Elixir requirement to 1.18.
@@ -542,10 +555,10 @@
542555
Install's lost-connection check is isolated as a whole-line launcher
543556
diagnostic, so ordinary error copy cannot trigger the restart-confirmation
544557
path.
545-
- `mix forecastle.relup` failed with `:systools is not available` in projects
558+
- `mix castle.relup` failed with `:systools is not available` in projects
546559
that do not themselves depend on `:sasl`, because Elixir prunes unused OTP
547560
applications from the build's code path.
548-
- `mix forecastle.relup` exited 0 when it had generated nothing.
561+
- `mix castle.relup` exited 0 when it had generated nothing.
549562
`:systools.make_relup/4` reports ordinary failure by returning `:error`, and
550563
Mix does not turn what a task returns into an exit status, so a build
551564
pipeline could not tell that generation had failed. Nothing removes a relup
@@ -554,7 +567,7 @@
554567
says what `systools` could not do and fails. Warnings that `systools` used to
555568
print for itself - an ERTS version change among them - are passed on rather
556569
than swallowed.
557-
- `mix forecastle.relup --outdir` was accepted and then ignored, so the relup
570+
- `mix castle.relup --outdir` was accepted and then ignored, so the relup
558571
was written to the current directory regardless, overwriting any unrelated
559572
relup already there. The switch now decides where the file goes, and the
560573
directory has to exist. Post-assembly still copies the relup it finds in the
@@ -573,7 +586,7 @@
573586
build that was silently packaging the wrong plan will now stop instead —
574587
before assembly begins, so a rejected relup leaves no half-built release
575588
behind for a later build to stumble over.
576-
- `mix forecastle.relup` discarded arguments it did not recognise, so a
589+
- `mix castle.relup` discarded arguments it did not recognise, so a
577590
mistyped switch, or a path given without one, generated a relup between
578591
releases the caller had not named instead of reporting the mistake. Omitting
579592
`--target` raised a `KeyError` from the middle of the task. Both are now

lib/forecastle.ex

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -171,7 +171,7 @@ defmodule Forecastle do
171171
# Checked in `pre_assemble/1`, before Mix has created anything, so all that is
172172
# left here is to put the bytes that were checked into the release.
173173
# Re-emitted from the term that was checked rather than copied from the file
174-
# again: `:file.consult/1` reopens the path, and a `mix forecastle.relup`
174+
# again: `:file.consult/1` reopens the path, and a `mix castle.relup`
175175
# running alongside the build can replace it in between, so a second read is
176176
# not necessarily the bytes that were checked. The format is the one
177177
# `systools` writes and `release_handler` reads - a UTF-8 coding comment and
@@ -190,11 +190,11 @@ defmodule Forecastle do
190190
end
191191
end
192192

193-
# The relup is produced by a separate `mix forecastle.relup` run, so nothing
193+
# The relup is produced by a separate `mix castle.relup` run, so nothing
194194
# about being here says it belongs to the release being assembled. Packaging
195195
# one for another version is worse than packaging none at all: nothing checks
196196
# it again, and `release_handler` applies it as this version's upgrade plan.
197-
# `mix forecastle.relup --outdir` makes that reachable - generation succeeds
197+
# `mix castle.relup --outdir` makes that reachable - generation succeeds
198198
# elsewhere and an older relup is left sitting here - and so does anything that
199199
# left a partial one behind: the task itself publishes by renaming a staging
200200
# file over the relup, and so cannot, but a copy or an editor interrupted
Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,11 @@
1-
defmodule Mix.Tasks.Forecastle.Relup do
1+
defmodule Mix.Tasks.Castle.Relup do
22
@moduledoc """
33
Generate a relup file between releases.
44
5-
`mix forecastle.relup` will generate a relup between a `target` release and
5+
This task is provided by `Forecastle`, Castle's build-time half, and named
6+
`castle.*` like the rest of the tooling a developer runs.
7+
8+
`mix castle.relup` will generate a relup between a `target` release and
69
any number of other releases. The paths specifed in the options should
710
be the paths to `.rel` files (but without the .rel extension)
811
@@ -893,7 +896,7 @@ defmodule Mix.Tasks.Forecastle.Relup do
893896
end
894897
end
895898

896-
# Unique per run: two `mix forecastle.relup` invocations sharing an `--outdir`
899+
# Unique per run: two `mix castle.relup` invocations sharing an `--outdir`
897900
# must not stage over each other, so the name carries both the OS process and a
898901
# counter within it. And unmistakable for a relup - a leading dot and a `.tmp`
899902
# suffix - because post-assembly reads the path `relup`, and a staging file

lib/mix/tasks/compile/appup.ex

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@ defmodule Mix.Tasks.Compile.Appup do
22
@moduledoc """
33
Compiles appup files into the application's ebin folder.
44
5+
This compiler is provided by `Forecastle`, Castle's build-time half.
6+
57
The `:appup` project key names a file, relative to the project file, that is
68
evaluated for its value. It must not introduce top-level bindings. Whatever it
79
returns is written to `<app>.appup` alongside the application's beams.

test/fixtures/sample/dep/mix.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ defmodule SampleDep.MixProject do
3434
3535
`SAMPLE_DEP_VSN` pins it independently of the sample's, so that the fixture
3636
can be assembled as a transition in which *only* project-owned applications
37-
changed. `mix forecastle.relup`'s `auto` strategy makes a transition a restart
37+
changed. `mix castle.relup`'s `auto` strategy makes a transition a restart
3838
when the version of an application the project does not own moved, and this
3939
application - a dependency of the sample - otherwise always moves with it.
4040
Unset, which is how every other suite builds the fixture, it moves in step as

test/forecastle/assembly_test.exs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -573,7 +573,7 @@ defmodule Forecastle.AssemblyTest do
573573
end
574574

575575
test "is refused when it is an upgrade plan for another version" do
576-
# The relup comes from a separate `mix forecastle.relup` run, so a stale
576+
# The relup comes from a separate `mix castle.relup` run, so a stale
577577
# one can be sitting here - `--outdir` sends a successful generation
578578
# somewhere else and leaves this one behind. Packaging it would hand
579579
# `release_handler` the wrong version's instructions.

test/forecastle/relup_test.exs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
defmodule Forecastle.RelupTest do
22
@moduledoc """
3-
Drives `mix forecastle.relup` against two really-assembled releases.
3+
Drives `mix castle.relup` against two really-assembled releases.
44
55
Generating a relup needs two releases on disk, each with its `.rel` file and
66
the `.appup` that carries the upgrade instructions, so there is no smaller
@@ -34,7 +34,7 @@ defmodule Forecastle.RelupTest do
3434
use Forecastle.ReleaseCase
3535

3636
alias Forecastle.Fixture
37-
alias Mix.Tasks.Forecastle.Relup
37+
alias Mix.Tasks.Castle.Relup
3838

3939
@from "0.1.0"
4040
@to "0.1.1"
@@ -634,7 +634,7 @@ defmodule Forecastle.RelupTest do
634634
end
635635

636636
test "does not collide with another run publishing into the same directory", ctx do
637-
# The staging file is named per run for this: two `mix forecastle.relup`
637+
# The staging file is named per run for this: two `mix castle.relup`
638638
# invocations sharing an --outdir must not stage into the same file, or one
639639
# could publish a relup that is partly the other's. Whichever wins the
640640
# rename, the file is one of them whole.
@@ -850,9 +850,9 @@ defmodule Forecastle.RelupTest do
850850

851851
defp rel(release, vsn), do: Path.join(release, "releases/#{vsn}/sample")
852852

853-
defp relup(args, vsn), do: mix(["forecastle.relup" | args], env(vsn))
853+
defp relup(args, vsn), do: mix(["castle.relup" | args], env(vsn))
854854

855-
defp relup!(args, vsn), do: mix!(["forecastle.relup" | args], env(vsn))
855+
defp relup!(args, vsn), do: mix!(["castle.relup" | args], env(vsn))
856856

857857
# The task builds nothing, but Mix still loads the project around it. Pointing
858858
# it at the build tree the target release was assembled in keeps it from

test/support/deployment.ex

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -44,11 +44,11 @@ defmodule Forecastle.Deployment do
4444
args = ["--target", rel_path(to, to_vsn), "--fromto", rel_path(from, from_vsn)]
4545

4646
Fixture.mix!(
47-
["forecastle.relup" | args ++ extra_args],
47+
["castle.relup" | args ++ extra_args],
4848
[{"SAMPLE_VSN", to_vsn}, {"MIX_BUILD_ROOT", Path.join(workspace, "_build-#{to_vsn}")}]
4949
)
5050

51-
assert File.exists?(relup), "mix forecastle.relup did not produce a relup"
51+
assert File.exists?(relup), "mix castle.relup did not produce a relup"
5252

5353
# And that it is a plan between these two versions, not merely a file.
5454
contents = File.read!(relup)

0 commit comments

Comments
 (0)