# general


09/20/2022, 7:00 AM
I am trying to write a "rule" (I assume I am on the correct path) so learn about plugins with the ultimate aim of writing some nice versioning backend logic that brings in many different versioning strategies (semver, calver, gitcommish, conventional-commits-semver) To get there I want to build up a few practical examples: The first place I wanted to understand is how plugins works and specifically, want to just tag a docker image.
Copy code
    dependencies=[":the_python_pkg", ":docker_resources"],
is coming from a rule generated in a plugin This is the "test plugin" i have written:
Copy code
# pants-plugin/versioning/
import os
from pants.engine.rules import collect_rules, rule

async def the_version() -> str:
    return os.popen('git --no-pager describe --always --dirty --broken').read()

def rules():
    return collect_rules()
However when
./pants package path/to:docker
is run I am expecting the docker_image tag to pickup the "string" from the
however pant` does not register the rule as a symbol ? (maybe it's not a rule I need)
Copy code
MappingError: Failed to parse ./services/my-image/BUILD:
Name 'the_version' is not defined.

If you expect to see more symbols activated in the below list, refer to <> for all available backends to activate.

All registered symbols: ['_generator_sources_helper', 'archive', 'build_file_dir', 'docker_image', 'experimental_run_shell_command', 'experimental_shell_command', 'file', 'files', 'helm_artifact', 'helm_chart', 'helm_unittest_test', 'helm_unittest_tests', 'http_source', 'parametrize', 'pex_binaries', 'pex_binary', 'pipenv_requirements', 'poetry_requirements', 'python_artifact', 'python_distribution', 'python_requirement', 'python_requirements', 'python_source', 'python_sources', 'python_test', 'python_test_utils', 'python_tests', 'relocated_files', 'resource', 'resources', 'setup_py', 'shell_source', 'shell_sources', 'shunit2_test', 'shunit2_tests', 'target']
My goal for this first step is to get
to "auto collect" the "GIT_COMMIT" version ref: and provide it as a variable or via a function (like I tried above). Such that
Copy code
./pants package src/example:demo
Builds a docker image with
demo:$(git rev-parse HEAD)


09/20/2022, 2:59 PM
So a fundamental fact of the Pants rule system is that it only exposes types and not functions. You can request an instance of the type an @rule returns but you cannot call any @rule by name (and you definitely can't call rules from BUILD files! its the other way around - rules can read data defined in BUILD files). This is pretty central to the pluggability of the system currently but it also makes things not straight forward to grok when you first encounter plugins and rules. Although Core Concepts does outline core concepts there is no real high level overview afaict that shows how you add new data to act on ( and then read that data in a rule and plug that rule's results into an existing goal . There are more specific guides for more narrow tasks: but yours is not directly covered by those.


09/20/2022, 3:09 PM
I'll add, part of the rule engine is cacheability as well. As your rule stands, the inputs to the rule dont' change when
state changes, so the result might be cached when you change commits. You might try using the type defined here as an input to your rule.
Feel free to reach out as you journey along your plugin. There's a bit of a learning curve, and we're here to help!


09/20/2022, 8:50 PM
Thanks Joshua. Is there any documentation on the state lifecycle (phase X before phase Y) ? So what I am thinking is (a few things). environment fields need to be read in 'at some point' and cached. where in the lifecycle does that occur - and are ENV vars "monitored" the same way Files are (which i observe from time to time)


09/20/2022, 8:56 PM
The rule graph itself represents the "phases". All of your inputs will be computed (or cached) before your rule runs. And your inputs are your function's parameters (annotated)