Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: support for complex hook plugin configuration #164

Conversation

superewald
Copy link

This PR adds support for complex hook plugin configuration as requested in #163.

implementation

As this change is a little more advanced I'll describe the important details below.

changes to config structure

In order to support complex hook plugin configuration the config structure had to be changed a little:

{
  "plugins": {
    "hooks": {
      "<plugin>@<version>": {
        "<key>": "<any json value>"
      },
    }
  }
}
  • plugins.hooks.<plugin>@<version> now supports any json value/structure and nesting
  • this change also ensures hook plugin options are not mixed up if two plugins use the same key

changes to hook plugin Init function

  • Hook.Init function was removed from the interface and is checked at runtime through reflection to support variable arguments
  • the hooks.Server.Init callback validates the Hook.Init function of the plugin and parse the plugins.hooks.<plugin>@<version> json to the type of the first argument of HookImpl.Init
    • the signature of HookImpl.Init must be func (*<HookImpl>) Init(<any structure>) error or hooks.Server.Init will throw an error
  • the HookImpl.Init function accepts map[string]string, thus no changes to existing plugin code is required (plugin must be compiled with newer semantic-release tho; see drawbacks for details)
type MyHook struct {}
type MyHookOpts struct {
	List []string
}

func (mh *MyHook) Init(opts MyHookOpts) error {
	log.Printf("list: %v", opts.List)
	return nil
}

// ... other function implementations of the Hook interface

drawbacks

This solution comes with some drawbacks I couldn't solve right now:

  1. the Init function was removed from the Hooks interface, thus compiling plugins without or with invalid Init function will succeed
    • this is necessary if the options should be parsed automatically since the first argument to Init needs to accept different types
    • an alternative would be to use Init(interface{}) and let the plugin author handle the conversion/decoding of the options to its appropriate type
  2. hook plugins compiled with the old Hook interface will stop work due to changes to the hooks.Server function. They won't produce errors but silently do nothing. Thus, every plugin has to be compiled against this change.
    • this could lead to problems with cached hook plugin installations (only if plugins aren't auto-updated which I dont know semantic-release does atm).
    • this also means custom hook plugins which are not maintained anymore will stop working
    • above issues may be preventable by introducing a breaking change version for semantic-release

to do

As this is a draft and I'm unsure if it gets picked up at the moment, there are a few things I will implement after a positive response:

  • add compatibility for older config structure (maybe useful if end users are unable or too lazy to change the config)
  • (optionally) revert to Init(interface{}) if the missing interface function is a huge problem/no-go
  • (optionally: if feature request: provide context to plugins #162 is rejected) merge common config with the hook plugin config

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants