Skip to content

Guardrails / Collectors

PHP project ​

The Composer project in the project directory: the package it declares, the PHP version and extensions it asks for, the packages it requires and which of them are pinned, and whether the lock file is committed.

Facts keyphp
Versionv1
Scriptphp.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": ["php"]
}
python
php = guardrail.facts("php")

Facts ​

These are the fields of the document php 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 composer.json.
sourcesEvery manifest that was read and understood. A manifest the reader could not handle is in unparsed instead.
declaredThe PHP version the project asks for, or null when it asks for none. config.platform.php wins over require.php, because it is the version Composer resolves against.
declared.versionConstraint exactly as written, such as ^8.2 or 8.2.18.
declared.sourceFile declaring it, from the directory the CLI runs in.
declared.pinnedWhether the constraint names one exact version rather than a range. A ^, a ~, a >=, a * or a | is not pinned.
typeThe type the manifest declares, such as library or project, or null when it declares none and library is implied.
projectsThe one package the manifest declares. Composer has no workspaces, so this is always a single entry.
projects[].pathDirectory of the package, from the directory the CLI runs in, always directory itself.
projects[].manifestThat package's composer.json, from the directory the CLI runs in.
projects[].nameName the manifest declares, such as company/widget, or null when it declares none.
dependenciesWhat the manifest requires, split by whether the project asks for it itself.
dependencies.directEvery package that require and require-dev name. The php constraint and the ext- and lib- platform requirements are left out, because they are not packages.
dependencies.direct[].namePackage name, such as symfony/console.
dependencies.direct[].versionConstraint exactly as written, such as ^7.0.
dependencies.direct[].scopesWhich of require and require-dev declare it.
dependencies.direct[].sourceManifest declaring it, from the directory the CLI runs in.
dependencies.direct[].pinnedWhether the constraint names one exact version. A ^, a ~, a range, a *, a dev- branch or a @ stability flag is not pinned.
dependencies.transitiveAlways empty. What composer.lock resolves is not read: lockfiles says whether one is committed.
platformEvery ext- and lib- requirement the manifest names, which is what the runtime has to carry rather than what Composer installs.
platform[].nameRequirement name, such as ext-json.
platform[].versionConstraint exactly as written, such as *.
scriptsNames of the scripts the manifest declares. Names only, because a script body can carry a token.
lockfilescomposer.lock when it is committed, from the directory the CLI runs in. An application without one resolves differently on every install.
unparsedEvery manifest the reader could not handle, 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 php collector gathers from an example project:

json
{
  "directory": ".",
  "exists": true,
  "manifest": "composer.json",
  "sources": [
    "composer.json"
  ],
  "declared": {
    "version": "^8.2",
    "source": "composer.json",
    "pinned": false
  },
  "type": "project",
  "projects": [
    {
      "path": ".",
      "manifest": "composer.json",
      "name": "company/widget"
    }
  ],
  "dependencies": {
    "direct": [
      {
        "name": "symfony/console",
        "version": "^7.0",
        "scopes": [
          "require"
        ],
        "source": "composer.json",
        "pinned": false
      },
      {
        "name": "monolog/monolog",
        "version": "3.6.0",
        "scopes": [
          "require"
        ],
        "source": "composer.json",
        "pinned": true
      },
      {
        "name": "phpunit/phpunit",
        "version": "^11.1",
        "scopes": [
          "require-dev"
        ],
        "source": "composer.json",
        "pinned": false
      }
    ],
    "transitive": []
  },
  "platform": [
    {
      "name": "ext-json",
      "version": "*"
    }
  ],
  "scripts": [
    "lint",
    "test"
  ],
  "lockfiles": [
    "composer.lock"
  ],
  "unparsed": []
}

Collected for ​

GuardrailCategoryInputs
php/dependencies-constrainedphpprojectDir
php/lockfile-committedphpprojectDir
php/version-declaredphpprojectDir

All collectors

Buildnote Limited
Registered in England and Wales, Reg: 16140412