Skip to content

Guardrails / Collectors

Elixir build ​

The Mix build in the project directory: the application it declares, the Elixir version it asks for, every application of an umbrella, the dependencies each manifest names with their environments and origins, and the lock file beside them. mix.exs is Elixir rather than a declaration, so what it declares conditionally is not seen and scanned says so.

Facts keyelixir
Versionv1
Scriptelixir.py
Timeout30 seconds

Inputs ​

InputDescriptionDefaultEnvironment
projectDirDirectory holding the project, relative to the directory the CLI runs in..GUARDRAIL_INPUT_PROJECTDIR

When a guardrail declares an input with the same name, it passes its value through. That means you set these values in the guardrail's configuration in buildnote.json.

A guardrail asks for these facts by name and reads them back by the same name:

json
{
  "collect": ["elixir"]
}
python
elixir = guardrail.facts("elixir")

Facts ​

These are the fields of the document elixir collects. In a path, [] means each entry of the list before it, and [path] means a key of the object before it.

FactMeaning
directoryThe project directory set by the guardrail's projectDir input, relative to the directory the CLI runs in. Every other path this collector reports is also relative to the directory the CLI runs in, so it resolves from where you invoked the CLI, not from wherever the collector happened to run.
existsWhether that directory exists. When it doesn't, nothing else is collected.
manifestPath of the primary manifest, from the directory the CLI runs in, always mix.exs.
sourcesEvery manifest that was read, in the order they were read.
scannedEvery manifest that is Elixir rather than a declaration and was read by pattern. A dependency added inside a condition or built by a function is not seen, so dependencies read from one of these is a minimum, not the complete list.
declaredThe Elixir version the project asks for, or null when it asks for none.
declared.versionConstraint exactly as written, such as ~> 1.16.
declared.sourceManifest declaring it, from the directory the CLI runs in.
declared.pinnedWhether the constraint names one exact version rather than a range. A ~>, a >= or an or is not pinned.
appThe application name the project function declares, such as widget, or null when the reader could not see one.
versionThe version the project function declares, such as 1.2.3, or null.
umbrellaWhether the project declares an apps_path, which makes it an umbrella whose real applications live under that directory.
projectsThe root application, followed by every application under the umbrella's apps_path.
projects[].pathDirectory of the application, from the directory the CLI runs in; directory itself for the project directory.
projects[].manifestThat application's mix.exs, from the directory the CLI runs in.
projects[].nameApplication name it declares, or null when the reader could not see one.
dependenciesWhat the manifests declare, split by whether the project asks for it itself.
dependencies.directEvery dependency tuple the reader saw, in the order they appear.
dependencies.direct[].namePackage name, such as phoenix.
dependencies.direct[].versionRequirement exactly as written, such as ~> 1.7.0, or null when the tuple names none because it comes from a path or a git URL.
dependencies.direct[].scopesEnvironments the only option names, such as dev and test, or default when the tuple names none and it is compiled in every environment.
dependencies.direct[].sourceManifest declaring it, from the directory the CLI runs in.
dependencies.direct[].pinnedWhether the requirement names one exact version. A ~>, a >=, a git URL or a path is not pinned.
dependencies.direct[].originWhere it comes from: hex, git when the tuple carries a git: or github: option, or path when it carries a path: option.
dependencies.transitiveAlways empty. What mix.lock resolves is not read: lockfiles says whether one is committed.
lockfilesmix.lock when it is committed, from the directory the CLI runs in. It carries the checksum of every package, so an application without one resolves and verifies differently on every build.
unparsedEvery manifest the reader could not open, so a guardrail can tell a project that declares nothing apart from one that could not be read.
unparsed[].pathPath of that manifest, from the directory the CLI runs in.
unparsed[].reasonWhy the reader could not handle it.

If a collector can't finish, it prints what it gathered so far along with an incomplete key that says why. Facts after the point where it stopped are missing, so a check that depends on them should read incomplete first.

Example facts ​

Here are the facts the elixir collector gathers from an example project:

json
{
  "directory": ".",
  "exists": true,
  "manifest": "mix.exs",
  "sources": [
    "mix.exs"
  ],
  "scanned": [
    "mix.exs"
  ],
  "declared": {
    "version": "~> 1.16",
    "source": "mix.exs",
    "pinned": false
  },
  "app": "widget",
  "version": "1.2.3",
  "umbrella": false,
  "projects": [
    {
      "path": ".",
      "manifest": "mix.exs",
      "name": "widget"
    }
  ],
  "dependencies": {
    "direct": [
      {
        "name": "phoenix",
        "version": "~> 1.7.11",
        "scopes": [
          "default"
        ],
        "source": "mix.exs",
        "pinned": false,
        "origin": "hex"
      },
      {
        "name": "jason",
        "version": "1.4.1",
        "scopes": [
          "default"
        ],
        "source": "mix.exs",
        "pinned": true,
        "origin": "hex"
      },
      {
        "name": "credo",
        "version": "~> 1.7",
        "scopes": [
          "dev",
          "test"
        ],
        "source": "mix.exs",
        "pinned": false,
        "origin": "hex"
      },
      {
        "name": "queue",
        "version": null,
        "scopes": [
          "default"
        ],
        "source": "mix.exs",
        "pinned": false,
        "origin": "path"
      }
    ],
    "transitive": []
  },
  "lockfiles": [
    "mix.lock"
  ],
  "unparsed": []
}

Collected for ​

GuardrailCategoryInputs
elixir/lockfile-committedelixirprojectDir
elixir/no-git-dependencieselixirprojectDir
elixir/version-declaredelixirprojectDir

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412