Skip to content

Plugins

Steve Manuel edited this page Jan 15, 2019 · 4 revisions

Writing a Protolock Plugin

If you find the need to extend the default checks in protolock, you probably want to create a plugin. Plugins are executable programs located in your system's $PATH or OS-specific equivalent.

To call plugins from protolock, ensure an executable is available on the system running protolock, and is named the same value passed to the --plugins option when calling the protolock status command. For example:

$ protolock status --plugins=my-plugin,your-plugin

Note: If you're writing your plugin in Go, see the protolock/extend package, which should help simplify development.

In the case above, both my-plugin and your-plugin must be executable programs installed and named by the same names used in the plugin invocation.

The plugin is executed by protolock and is sent a serialized JSON representation of the data accumulated by protolock reading the proto.lock file (the "current" Protolock), and parsing your .proto files (the "updated" Protolock).

This data is sent to your plugin's stdin in the following structure, and must be deserialized by your plugin:

{
    "current": { // "current" is the protolock representation of the "proto.lock" file on disk
        "definitions": [
            {
                "protopath": "",
                "def": {
                    "enums": [
                        {
                            "name": "",
                            "enum_fields": [
                                {
                                    "name": "",
                                    "integer": 0
                                }
                            ],
                            "reserved_ids": [],
                            "reserved_names": [],
                            "allow_alias": false
                        }
                    ],
                    "messages": [
                        {
                            "name": "",
                            "fields": [
                                {
                                    "id": 0,
                                    "name": "", 
                                    "type": "",
                                    "is_repeated": false
                                }
                            ],
                            "maps": "",
                            "reserved_ids": [],
                            "reserved_names": [],
                            "filepath": "",
                            "messages": [],
                            "options": ""
                        }
                    ],
                    "services": [
                        {
                            "name": "",
                            "rpcs": {
                                "name": "",
                                "in_type": "",
                                "out_type": "",
                                "in_streamed": false,
                                "out_streamed": false
                            },
                            "filepath": ""
                        }
                    ],
                    "imports": [
                        {
                            "path": ""
                        }
                    ]
                }
            }
        ]
    },
    "updated": { // "updated" is the protolock representation of your .proto files in your tree
        "definitions": [...] // "definitions" are of the same structure as the ones defined in "current"
    }
}

You can find more detail about this data by examining the source types in the parse.go file within this repository.

Once your plugin has read and processed the data, checking for any custom rules you have implemented, it is the plugin's responsibility to then add any number of warnings and/or an error message, which will be reported back to the protolock user.

The warnings and/or error message should be added to the original data sent to your plugin, and sent to stdout in the following structure:

{
    "current": {...},
    "updated": {...},
    "plugin_warnings": [
        {
            "filepath": "",
            "message": ""
        }
    ],
    "plugin_error_message": ""
}

Since your plugin is run independently from and in parallel with other plugins, you may omit the current and update fields from the data sent by your plugin to stdout. Support for ordered serial execution may be introduced in the future, at which point, returning all of the current and updated data would be required. Omitting these fields should only be done as a performance enhancement if your plugin is running slowly due to a large JSON payload sent between the processes.

See plugin examples in the "plugin-samples" directory in this repository.

Clone this wiki locally