Skip to content

INV groovy syntax

benjboyer edited this page Feb 10, 2021 · 10 revisions

INV's has its own DSL using the Groovy framework.

This is the syntax for implementing an INV:

/**
    Adds a new debugging message.
    It is available in the whole script scope. Thus, inside any INV.
    
    Per example:    
        inv {
            ...
            step {
                debug "Something"
            }
        }

    @optional
    @type Object
    @default None, a value is required
*/
debug("My message")

/**
    Load a remote REPO file and add its INVs into the current execution.

    @optional
    @type String
    @default None, a value is required
*/
load("URL")

/**
    Creates a new INV object to be processed.
    
    @optional
    @type Closure
    @default None, a value is required
*/
inv {
    /**
        Defines the name of the new INV object. Defaults to Script name
    
        @optional
        @type String
        @default Current file name. Per example filename "MyInv.groovy" would give "MyInv" and
                 "MyInv/inv.groovy" would result "MyInv"
    */
    name "MyName"

    /**
        Defines the path for this Inv. The parent folder of the physical file is the default value.
        
        @optional
        @type String
        @default None, a value is required
    */
    path "./my/path/..."

    /**
        Defines the markdown description for this INV.
        
        @optional
        @type String
        @default None, a value is required
    */
    markdown "My **markdown** description"

    /**
        Determines if this INV should be in the first position when digestion occurs.
        By default, it is false.    

        @optional
        @type Boolean
        @default None, a value is required
    */
    pop false
    
    /**
        Determines if this INV should be in the last position when digestion occurs.
        By default, it is false.
    
        @optional
        @type Boolean
        @default None, a value is required
    */
    tail false

    /**
        Defines custom tags to be attached during the whole processing.
        Tags are synonyms to labels.

        They enable this INV to a 'when tags' features.
                
        Tags are also available as a property.
        Per example:
            tags(myType: 'type1') 
            require { Type(tags.myType) } 

        @optional
        @type Map<String, String>
        @default None, a value is required
    */
    tags([my: 'tag'])

    /***
        Defines a shorthand broadcast statement. 
        Each broadcast needs a *name* (below it's "MyBroadcastStatement").
        Also, it allows associating a unique identifier.  
        
        @optional
        @type Object
        @default None, the value required
    
        @param id
            Sets the unique identifier.             
    
            @type Object, Map, Closure
            @default By default, identifier uses the String "undefined".
    */
    broadcast { MyBroadcastStatement }
    broadcast { MyBroadcastStatement("myFirstId") }
    broadcast { MyBroadcastStatement(myId: 1) }
    broadcast { MyRequireStatement { myId: $previousResponse } }

    /**
        Defines a broadcast statement using specific options and events
        It is a sub-option of the shorthanded broadcast statement.
    
        @type Object
        @default None, a value is required
    */
    broadcast { MyBroadcastStatement } using {
    
        /**
            Same as the shorthanded version using the syntax 'inv.MyName(myId)', but does not have a default value.
            
            @optional
            @type Object, Map, Closure
            @default None, a value is required
        */
        id "String"
        id myMap
        id { $previousResponse }

        /**
            Defines the markdown description for this broadcast statement.
            
            @optional
            @type String
            @default None, a value is required
        */
        markdown "My markdown description"
        
        /** 
            Defines a callback when a broadcast is ready to process.
            It allows returning a response to any requirement statement (see below).
            
            Per example, you could return :
                ready  {
                    return [
                        myProperty: "foo",
                        myMethod: { "bar" }
                    ]
                }
                      
            To define a default callback upon resolution on the REQUIRE side, use the method name '$'.
            Per example:
                ready {
                    return [
                        $: { println "foobar" }
                    ] 
                }
            In other words, each time a requirement statement is met with this broadcast, 'println "foobar"' will be raised.

            REALLY IMPORTANT:
                Upon calling a method from the response, EVERY broadcast or require made are assigned to
                the callee INV and not to this one.
                In other words, each response methods define here is DELEGATED to its callee.
    
            @optional
            @type Closure
            @default None, a value is required
            @return A Map object. Null is allowed.
        */
        ready { 
            // Your code here...
        }
    }

    /**
        Defines a shorthand requirement statement. 
        Each requirement needs a *name* (below it's "MyRequireStatement").
        Also, it allows associating a unique identifier.  
        
        @optional
        @type Object
        @default None, the value required
    
        @param id
                Sets the unique identifier.             
    
                @type Object, Map, Closure
                @default By default, identifier uses the String "undefined".
    */
    require { MyRequireStatement }
    require { MyRequireStatement("myFirstId") }
    require { MyRequireStatement(myId: 1) }
    require { MyRequireStatement { myId: $previousResponse } }

    /**
        Defines a requirement statement for which the broadcast "response" is automatically avaiable by 
        calling a property.
        You may use the 'into' option with others, such as 'using'.        
        By convention, the name of the property should starts with a lowercase preceded by the '$' character. 
        You may also use the property to chain statements. 

        Per example:
            Will work:
                require { Something }
                broadcast { Else { $Something }

            Will work:
                require { Something } into '$something'
                broadcast { Else } using {
                    ready {
                        $something...
                    }
                }

            Will NOT work:
                require { Something } into '$something'
                require { Else($something...) }
    
        @optional
        @type String
        @default Yes, it uses the statement's name, with its first letter lowercase and a preceding '$'.
                 Per example "require { Something }", would give '$something'. 
                 It is case sensitive 
    */ 
    require { MyRequireStatement } into "$myResponse"

    /**
        Defines a requirement statement using specific options and events
        It is a sub-option of the shorthanded require statement.
    
        @type Object
        @default None, a value is required
    */
   require { MyRequireStatement } using {
    
        /**
            Sames as the shorthanded version using the syntax 'inv.MyName(myId)', but does not have a default value.
            
            @optional
            @type Object, Map, Closure
            @default None, a value is required
        */
        id "String"
        id myMap
        id { $previousResponse }

        /**
            Defines the markdown description for this require statement.
            
            @optional
            @type String
            @default None, a value is required
        */
        markdown "My **markdown** description"
    
        /**
            Indicates if this requirement is allowed to unbloat.
            By default, false.

            Unbloat occurs when no statements match the requirement statement.  
            It is an attempt to "unbloat" and keep on the work.
            Usually, only 'non-vital' OR omnipresent requirements should be unbloatable. For example an Artifact.            

            @optional
            @type Boolean
            @default None, a value is required
        */
        unbloatable Boolean
    
        /**
            Indicates if this statement uses the default value of the matching broadcast. 
         
            Per example:
                inv.MyGenericBroadcast using {
                    ready {[
                        $: {
                            return path.listFiles()
                        },
                        listFiles: { path -> 
                            ...
                        }
         
                    ]}
                }
            Enabling "defaults" would return the value from "$".
            Disabling "defaults" would return the encapsulating object, thus making "listFiles" available.

            
            @optional
            @type Boolean
            @default Yes, value is "true"
        */
        defaults Boolean
  
        /**
            Defines a callback when the requirement statement is met.
            
            Here's the available properties within the callback:
        
                - response: (Object) An object reference to methods and/or properties available by the matching broadcast statement. 
            
                - resolvedBy: (String) The name of the matching broadcast.

            Here's the available methods within the callbackL

                - response(): (Object) The raw value of the broadcast response object.
        
            IMPORTANT: When calling a method from a response, ALL delegated statements (broadcast or require) are made by the calling (this) INV - not by the broadcast's INV.

            @optional
            @type Closure
            @default None, a value is required
        */
        resolved { 
            // Your code...          
        } 

        /**
            Defines a callback when a requirement statement is NOT met AND is unbloatable.

            @optional
            @type Closure
            @default None, a value is required
        */
        unresolved {
            // Your code here...
        }
    }

    /**
        Defines a callback when the INV is at the beginning of the sequencing process.
    
        @optional
        @type Closure
        @default None, a value is required
    */
    ready {
        // Your code here...
    }

    /**
        Defines a new step that acts as a "group wait".
        It is raised only when ALL previous statements (require or broadcast) are met.
    
        It is a way to execute arbitrary code between a bunch of statements.
        
        You can have an embedded step inside another step.
        it could help with conditioning a step depending on the current INV state. 
        Embedded steps are added at the end of the step list.
        Per example, these are equivalent:
            Example1:
                step {
                    step { }
                }
            Example2:
                step {
                }    
                step {
                }

        @optional
        @type Closure
        @default None, a value is required
    */
    step {
        // Your code here...
    }

    /**
        Allows trapping system-wide events about other INV.
        IMPORTANT: When's event are not considered 'require' links.

        Callbacks are only fired once (even for 'any' scope).
        
        A when's event CAN'T apply for the current INV where it is defined.
        Per example:
            // Will not work
            inv { 
                tags(my: 'tag')
        
                when any tags (my: 'tag') ...
            }
            // Will work
            inv {
                tags(my: 'tag')
            }
            ...
            inv {
                when any tags (my: 'tag') ...
            }
    
        @optional
        @default None, a value is required
    
        @param scope
                Sets the scope.
                Only valid values are: all, any             
            
                All imply that all matchable INV qualifies before firing the callback.
                
                Any implies that only one matchable INV needs to qualify before firing the callback

                @type When event scope
                @default None, the value required

        @param type
                Sets the filtered type.
                Only valid values are: tags, name             
        
                Tags imply only tags are filtered when qualifying.
                Per example:
                    inv { 
                        tags(my: 'tag')
                    }
                    ...
                    inv {
                        when any tags (my: 'tag') ...
                    }

                Name imply only names are filtered when qualifying.
                Per example:
                    inv { 
                        name 'my-name'
                    }
                    ...
                    inv {
                        when any name ('my-name') ...
                    }

                @type When event type
                @default None, the value required

        @param value
                Sets filtered value             
        
                @type Object, Map
                @default None, the value required

        @param event
                Sets the event trigger.
                Only valid values are: available, completed             
            
                Available implies an INV is only required to be registered.
                Completed implies an INV is required to have no remaining statements to process, thus being completed.

                @type When event trigger
                @default None, the value required
    
        @param callback
                Sets the callback closure to be fired when all the criteria are met for this when's event.

                @type Closure
                @default None, the value required

    */
    when [all|any] [tags|name] ("myValue") [available|completed] {
        // callback
    }
}

For more examples, check here