MobDev.Release.Publish (mob_dev v0.5.7)

Copy Markdown View Source

Replaces scripts/release/publish.sh — uploads built tarballs to a GitHub release tagged otp-<hash>. The release is created if it doesn't exist; existing assets with matching names are deleted before upload (gh release upload won't replace by default).

Why this module carries the most error categories

Of the five MobDev.Release.* orchestrators this is the one most likely to fail through no fault of ours — GitHub goes down, gh auth expires, the local network drops. The shell version of this step blobs all of those together as exit 1; the user can't tell whether it's their problem or ours. This module classifies every gh failure into one of:

  • :auth_required — gh CLI isn't authenticated, or token lacks repo scope. Hint suggests gh auth login --scopes "repo,write:packages".
  • :infra_unreachable — GitHub returned 5xx or the network's down. Detail carries the first line of gh's stderr so it's obvious what to check on status.github.com.
  • :precondition_failed — no tarballs in out_dir matching hash. Hint points the user at mix mob.release.tarball all.
  • :cmd_failed — fallback for unexpected gh failures (e.g. malformed tag, write permission denied on a non-our repo).

This is exactly the "is GitHub down or am I broken?" distinction the build-system migration plan called for. Test coverage exercises each category against a representative gh stderr snippet.

Public API

MobDev.Release.Publish.publish()                    # defaults
MobDev.Release.Publish.publish(repo: "fork/mob")    # publish to fork
MobDev.Release.Publish.publish(assets: ["otp-android"])  # subset

Returns {:ok, %{tag, repo, assets}} on success or a tagged error.

What it does end-to-end

  1. Resolve repo, hash, out_dir (env or opts).
  2. Discover which of the four canonical tarball basenames are present in out_dir for this hash. At least one must exist.
  3. gh release view otp-<hash> — exists?
    • If not (release not found), gh release create.
    • If 401/403, :auth_required.
    • If 5xx/network, :infra_unreachable.
  4. List the release's existing assets. For each one that overlaps with what we're about to upload, gh release delete-asset.
  5. Single gh release upload otp-<hash> <paths…>.
  6. Verify by re-listing assets — returned in info.assets.

Summary

Types

Successful publish result.

Functions

Canonical tarball basenames the publisher knows how to upload.

Classify a gh stderr/stdout line into one of :not_found, :auth, :infra, or :other. Public for testing — the regexes are the contract.

Default GitHub repo (mirrors publish.sh's ${REPO:=GenericJam/mob}).

Asset basenames that exist in out_dir for the given hash. Returns an ordered list (matching candidate_basenames/0 order).

Run the publish pipeline. See module doc for options.

Build the release tag for a hash (otp-<hash>).

Types

info()

@type info() :: %{tag: String.t(), repo: String.t(), assets: [String.t()]}

Successful publish result.

Functions

candidate_basenames()

@spec candidate_basenames() :: [String.t()]

Canonical tarball basenames the publisher knows how to upload.

classify(output)

@spec classify(String.t()) :: :not_found | :auth | :infra | :other

Classify a gh stderr/stdout line into one of :not_found, :auth, :infra, or :other. Public for testing — the regexes are the contract.

default_repo()

@spec default_repo() :: String.t()

Default GitHub repo (mirrors publish.sh's ${REPO:=GenericJam/mob}).

discover_assets(shell, out_dir, hash)

@spec discover_assets(module(), Path.t(), String.t()) :: [String.t()]

Asset basenames that exist in out_dir for the given hash. Returns an ordered list (matching candidate_basenames/0 order).

publish(opts \\ [])

@spec publish(keyword()) :: {:ok, info()} | MobDev.Release.Errors.t()

Run the publish pipeline. See module doc for options.

Recognized opts:

  • :repoowner/name (default: GenericJam/mob)
  • :hash — release hash. Default: detected from OTP_SRC git or $HASH.
  • :otp_src — OTP checkout for hash detection. Default per Helpers.
  • :out_dir — directory containing the built tarballs. Default per Helpers.
  • :assets — list of tarball basenames to upload. Each may be either the bare base ("otp-android") — in which case -<hash>.tar.gz is appended — or the full filename. Default: auto-discover any of the four canonical names that exist.

tag_for(hash)

@spec tag_for(String.t()) :: String.t()

Build the release tag for a hash (otp-<hash>).