Raxol. Release. PackageCheck
(Raxol v2.7.0)
View Source
Validates the Hex release train before publishing any package.
The check is deliberately release-train aware. The repo has package metadata on pre-alpha projects for local builds, but the public Hex train is smaller and ordered by inter-package dependencies.
Three layers run per package:
metadata -- project/package/docs keys, link sets, file globs that match something, docs extras that are actually packaged, and dependency requirements that agree with the version each dependency publishes.
provenance -- every file the package would ship is tracked by git, so publishing from a dirty tree cannot leak untracked content into a public registry.
mix hex.buildpackages the working tree, not the commit, so a green run on a dirty tree otherwise says nothing about what ships.tarball --
HEX_BUILD=1 mix hex.build --unpack, then the generatedhex_metadata.configis compared against the source project config. Comparing against the publish config would be circular: a dependency dropped by an env conditional inmix.exsis absent from both sides and produces no finding at all.
Summary
Functions
Returns every explicitly classified package project.
Compares the dependencies a project declares against the ones it publishes.
Returns the public Hex release train in publish order.
Returns the Raxol package dependencies relevant to a Hex publish.
Resolves the scratch directory the Hex builds unpack into.
Runs the metadata, provenance, and Hex build checks.
Selects packages according to the release checker options.
Lists the files a package would ship that git does not track, relative to
root.
Checks that every project under packages/ is classified in this module.
Checks that no package is published before a dependency it needs.
Types
@type report() :: %{ root: String.t(), packages: [package_report()], global_errors: [String.t()], errors: [String.t()] }
Functions
@spec all_packages() :: [package_spec()]
Returns every explicitly classified package project.
Compares the dependencies a project declares against the ones it publishes.
Audit the source config, never the publish config. Auditing the publish
config is circular: a dependency dropped by an env conditional in mix.exs
is missing from the publish config and from the tarball, so the two agree and
nothing is reported.
A public-train dependency that fails to reach the tarball is an error. A pre-alpha one is an intentional drop, but it still changes what Hex consumers get, so it is surfaced as a warning rather than as silence.
@spec public_packages() :: [package_spec()]
Returns the public Hex release train in publish order.
Returns the Raxol package dependencies relevant to a Hex publish.
Resolves the scratch directory the Hex builds unpack into.
build_root is deleted recursively, so it is confined under the project root
and may be neither the root itself nor an existing directory this checker did
not create. Without those gates run(build_root: ".") deletes the working
tree. The path is always interpreted relative to root; an absolute request
is jailed under it rather than honoured.
Runs the metadata, provenance, and Hex build checks.
Not safe to run concurrently with anything else in the same VM. Loading a
child project goes through Mix.Project.in_project/4, which changes the
working directory of the whole OS process, and the HEX_BUILD toggling around
it mutates the process environment. Both are global. Tests covering this
module are async: false for that reason.
@spec select_packages(keyword()) :: {:ok, [package_spec()]} | {:error, [String.t()]}
Selects packages according to the release checker options.
:only accepts atoms or strings. Strings are matched against known package
names rather than converted, so a typo cannot mint an atom from argv.
@spec untracked_package_files(String.t(), String.t(), keyword()) :: {:ok, [String.t()]} | :unavailable
Lists the files a package would ship that git does not track, relative to
root.
mix hex.build packages the working tree, not the commit, so a green check
on a dirty tree says nothing about what a publish actually ships. Returns
:unavailable when git cannot answer, which the run reports as a warning
rather than treating as a clean result.
Checks that every project under packages/ is classified in this module.
A package that exists on disk but appears in neither train is unclassified;
a classified package with no project on disk is missing. Either one means
the release train no longer describes the repo.
@spec validate_order([map()], [package_spec()]) :: [String.t()]
Checks that no package is published before a dependency it needs.
package_reports need only carry :app and :deps; the publish order is
the position of each package in release_train.
validate_project_config(spec, config, package_path, release_train \\ [%{app: :raxol_core, class: :public, path: "packages/raxol_core"}, %{app: :raxol_sensor, class: :public, path: "packages/raxol_sensor"}, %{app: :raxol_terminal, class: :public, path: "packages/raxol_terminal"}, %{app: :raxol_mcp, class: :public, path: "packages/raxol_mcp"}, %{app: :raxol_liveview, class: :public, path: "packages/raxol_liveview"}, %{app: :raxol_plugin, class: :public, path: "packages/raxol_plugin"}, %{app: :raxol_speech, class: :public, path: "packages/raxol_speech"}, %{app: :raxol_watch, class: :public, path: "packages/raxol_watch"}, %{app: :raxol, class: :public, path: "."}, %{app: :raxol_agent, class: :public, path: "packages/raxol_agent"}, %{app: :raxol_payments, class: :public, path: "packages/raxol_payments"}, %{app: :raxol_telegram, class: :public, path: "packages/raxol_telegram"}])
@spec validate_project_config(package_spec(), keyword(), String.t(), [package_spec()]) :: {[String.t()], [String.t()]}
Validates one loaded Mix project config against a package spec.