Hi there,

after huge interest for JCasC at Jenkins World, I wrote some minimalist
guide for plugin developers to understand requirements so your plugin is
well supported.

can read online here
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/REQUIREMENTS.md>,
but here's a copy so you can't say you didn't know :P

JCasC Requirements - guide for plugin maintainers

JCasC is designed so any plugin can be managed without the need to
implement any custom API, but still require plugins to respect some
contract, aka "*convention over extension*". This documentation is here to
explain plugin maintainers those conventions and provide guidance on
expected design.

[image: CasC is comming]
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/BraceYourselves.jpg>
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/REQUIREMENTS.md#overview>
Overview

JCasC relies on ability to introspect jenkins configurable components to
build a "data model" from a live jenkins instance. For this purpose it
relies on web UI data-binding conventions.

For legacy reasons, Jenkins do offer multiple ways to support UI
data-binding, but the sole one to be introspection friendly is to offer
@DataBoundSetter fields or setters in your code.

Surprisingly, this is well adopted by most plugins for Describable components,
but not for Descriptors, despite the exact same mechanism can be used for
both. And unfortunately, in many case the interesting components to offer
configuration one want to expose to JCasC is attached to a Descriptors.
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/REQUIREMENTS.md#check-list>
Check-list
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/REQUIREMENTS.md#rule-1-dont-write-code-for-data-binding>Rule
1: don't write code for data-binding

Check implementation of Descriptor#configure(StaplerRequest,JSONObject) in
your descriptors. This one should not use any of the JSONObject.get*() methods
to set value for an internal field. Prefer exposing javabean setter
methods, and use req.bindJSON(this,JSONObject) to rely on
introspection-friendly data-binding.

Within a Descriptor such setters don't have to be annotated as
@DataBoundSetter but we suggest to do anyway, as it make it clear about the
intent for such public methods.

sample :

public boolean configure(StaplerRequest req, JSONObject json) throws
FormException {
    smtpHost = nullify(json.getString("smtpHost"));
    replyToAddress = json.getString("replyToAddress");
    ...
    save();
    return true;
}

to be replaced by :

public boolean configure(StaplerRequest req, JSONObject json) throws
FormException {
    req.bindJSON(this, json);
    save();
    return true;
}
@DataBoundSetterpublic void setSmtpHost(String smtpHost) {
    this.smtpHost = nullify(smtpHost);
}
@DataBoundSetterpublic void setReplyToAddress(String address) {
    this.replyToAddress = Util.fixEmpty(address);
}

note: you might not even need to implement configure once #3669
<https://github.com/jenkinsci/jenkins/pull/3669> is merged.
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/REQUIREMENTS.md#rule-2-dont-use-pseudo-properties-for-optional>Rule
2: don't use pseudo-properties for optional

You might have a set of fields which only make sense when set altogether,
and have jelly view to use <f:optionalBlock>based on some boolean
pseudo-property to show/hidde the matching section in web UI.

Doing so require had-written data-binding code, so based on rule 1 should
be prohibited.

Hopefully there's a simple (and arguably better) way to handle this, by
just using nested components and group all related fields into an optional
sub-element.

sample :

<f:optionalBlock name="useAuth" title="${%Use Authentication}"
                 checked="${descriptor.username!=null}">
    <f:entry title="${%User Name}" field="username">    
          <f:textbox /> 
    </f:entry>
    ...

private String username;private Secret password;
public boolean configure(StaplerRequest req, JSONObject json) throws
FormException {
    if(json.has("useAuth")) {
        JSONObject auth = json.getJSONObject("useAuth");
        username = nullify(auth.getString("username"));
        password = Secret.fromString(nullify(auth.getString("password")));      
    }
}

to be replaced by :`

<f:optionalProperty field="Authentication" title="${%Use Authentication}"/>

private Authentication authentication;

With a fresh new Authentication Describable class to host username and
password, all the <f:optionalBlock> body being moved
Authentication/config.jelly view.

note: this also require some data migration logic, please read PLUGINS
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/PLUGINS.md>
for
a step by step migration guide.
<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/REQUIREMENTS.md#rule-3-define-a-test-case-if-you-can>Rule
3: define a test case if you can

Checking support for JCasC is easy as long as your plugin required java 8 /
jenkins 2.60+.

You just need CasC as a test dependency and a sample yaml file for your
component

<dependency>
      <groupId>io.jenkins</groupId>
      <artifactId>configuration-as-code</artifactId>
      <version>1.0</version>
      <scope>test</scope>
</dependency>

public class ConfigAsCodeTest {

    @Rule public JenkinsRule r = new JenkinsRule();

    @Test public void should_support_configuration_as_code() throws Exception {
        
ConfigurationAsCode.get().configure(ConfigAsCodeTest.class.getResource("configuration-as-code.yml").toString());
        assertTrue( /* check plugin has been configured as expected */ );
    }

Benefits for you to write such a testcase :

   - You confirm your plugin is well design regarding JCasC conventions
   - You offer users a sample configuration file
   - You will be able to detect breaking changes that may impact your users

<https://github.com/jenkinsci/configuration-as-code-plugin/blob/master/docs/REQUIREMENTS.md#rule-4-ping-us-in-case-of-doubts>Rule
4: ping us in case of doubts

Really, if you need any assistance getting your plugin to support JCasC,
want code review or anything, ping us on Gitter
<https://gitter.im/jenkinsci/configuration-as-code-plugin>.


-- 
Nicolas De Loof

-- 
You received this message because you are subscribed to the Google Groups 
"Jenkins Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/jenkinsci-dev/CANMVJzmkxLVPw0iYV5Jn8o6OiiSCWbmgBQpbrTRRyTmDyQLAUw%40mail.gmail.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to