Implementing DSLs in Groovy: A Comprehensive Guide

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello there and welcome to groovy DSL QuickStart interaction video today you are going to learn how you can build fluency cells and go to the programming language before we start let me show you what groovy version I'm using and this is a groovy free 0.2 on Java 1.8 here I have IntelliJ with some DSL and some of you probably knows this DSL this is Jenkins file and this is the declarative pipeline DSL syntax here on the bright side we have the SL class prepared for writing our DSL and if we look at the project tree structure you can see here is this jenkins file from the left side and here we have the dsl groovy class so if i try to run it at the moment you will see that this jenkins felt groovy fails of course because there is no pipeline function known in the scope of the script and we are going to fix this and a very important disclaimer this is only demo example how we can write groovy DSL this is not the Jenkins declarative pipeline DSL implementation pipeline DSL is much more complicated if it comes to how it's implemented here we will just use it as an example and we will try to mimic its behavior and by mimic I mean we will just get some console output and that's all there is no Jenkins involved in this demo we are going to run the script and see some output in a console log so okay let's start with our implementation then so first of all we need to satisfy this no signature of method pipeline so let's start with implementing simple static void pipeline method and this pipeline will expect Bossier and now if we go here we can just import static this function and now our example does not fail because this method is found it does nothing at the moment but it at least the components so what we have here we have a pipeline methods with some closure in this closure is represented here so we need to do something now the first thing you're going to learn about closures closures are very powerful especially there is the delegation mechanism let me show you what I what I mean by that so let's implement something like a pipeline dsl class and this class will have all these methods so it will have medical agent with some parameter we will introduce later there is also environment with closure and there is also stages so this class represents our VSL here what we need to do next is let me make this a little bit bigger here so we are going to initialize this pipeline DSL and then we will use delegation mechanism enclosures so each closure can be delegated to some other object what does it mean it means that when we are when we will be executing this closure this for instance this is just a method call with a closure parameter so this is a when we delegate it to DSL disclosure will search for environemnt method in the pipeline DSL it will find it so it will call this method on our legate object there is also another thing that we need to do in especially in our case we need to define resolve strategy there are different resolve strategies but in our case we are interested in delegate only it means that if specific method is not found in the legate in the object that we delegate to it won't try to find it elsewhere because like the delegate first the resolve strategy means that I will try to find it in the legate object first but then I will try to find it for instance in the owner of such closure and then we will just call this closure okay now we can run this pipeline and see it a little of course it fails because there is no property any because here what we what we see is there is a method agent invoked with some property any which does not exist in this pipeline DSL we can fix that let's introduce placeholder enum with a single value any and then we can try to to find it at this level right so now if we call this closure it fails because there is no agent method applicable for place holder right so let's do formal Inc and here we are going to print line running pipeline using any available agent okay let's run our example and we can see that the agent method was invoked the same goes for environment and stages was that you can see these methods are empty at the moment so the first thing you have learned is closure delegation and how powerful this mechanism is right now let's add something to our DSL but we can add some information for the compiler and first for the IDE we can use delegates to annotation and this delegates to annotation will tell the compiler what is the target of the legation for this specific closure so we can say that it delegates to pipeline DSL and now IDE recognizes those methods and we also going to specify strategy because delegates to by default it uses our first strategy so it could run to some incorrect code completions so let's set delegate only strategy on this as Welli this is something we should take care of to make sure that the resolved strategy on a closure matches the strategy on delegates - and now you can see these methods are recognized and if I try to call it as you can see I get the code completion here nice so this is the second thing we have learned delegates to annotation let's move to the environment method implementation let's say that we have static final mmm concurrent map string string called ANOVA and we are going to run these property settings on this environment map okay so first of all we will tell using legates to a mechanism that this closure delegates to map you can see it already changed here but if it comes to delegation strategy in this case we can use a little bit different mechanism Ravi has with methods and if we take a look how does method is implemented we will find that with method creates a copy of closure then it sets the whole strategy to delete first it sets delegate to the object that is method was in a vote on and then it calls the closure so what does it mean it means that if we use an of will and then we pass our closure it means that the body of this closure will be invoked on the this end map here okay as you've seen the strategy is delegate first so let's set this strategy resolve strategy as well okay and now maybe let's take a look if it works I will just print an environment after it's set and here you can see that these two environment variables are set correctly let's move to stages DSL part here we will need to introduce another DSL for the stages let's called stages DSL and let's say it has a single method called stage with name and some closure okay so this is our the stages DSL but we are going to do here yes we will create like a stage objects for every stage before we actually execute those stages okay so let's create stage class which has name and let's have let's say it has disclosure we can create a constructor here so this stages DSL let's say it had protected final list of stages and what it does is whenever this stage method here is executed by our DSL it will create a new stage object with the name and closure and we will store it in on this stages list okay so what we need to do is we will set the legate's two stages DSL so now you can see this method is recognized with the strategy delegate only so what we need to do here is stages DSL we set delegation to this DSL we set resolve strategy to delegate only and then we call the closure what happens after disclosure is called we will see that this DSL stages contains two stages objects right we have this is the first stage and here is the second stage okay so what we are going to do we will do DSL stages each stage and let's say that we are going to run such stage okay okay so our pipeline dsl executes those two stages of course there is no DSL that would recognize steps method so we need to add it here as well let's introduce stage DSL so here we will build DSL for this closure so it has steps so here we have this DSL for stage we can define it right here so the legates to stage the SL so steps methods is automatically recognized and we can set the strategy to delegate only and in this case we need to initialize this DSL here then we need to delegate it to the DSL of course as you can see we we do so many repetitions here so I guess extracting some helper function that sets always the delegate and delegate only strategy would be very helpful but this is only demo in this case so we call this closure on stage DSL and in this case let's say that we will just create steps class and for simplicity I will just define those functional steps functions here so we have SH with some scrapped we will have some object a sage with with a map and we will also have echo and now what we can do yes we're going to delegate disclosure two steps result strategy delegate only and we are going to call closure that's it and of course a in this case we need to send like it's two value steps so these steps are recognized and strategy delegate only of course okay we have written a lot of code let's run our Jenkins file groovy it doesn't fail but it goes here but nothing happens let's start with implementing echo function echo step which will just echo some message like that and if we run it we will see echo groovy rocks let's implement Sh step with Sh step we can execute some shell process so let's make this function our main function so we will call this Sh with the following map and as you can see here it tells me just that there is another sh function in this class with map our argument but let's learn about named parameters here so we can add named params annotation here and we can define a list of parameters that this map contains so in our case there are two parameters the first is script it's type is string and it's required there is also second named parameter returned STD out and it's type is boolean so now when I call this Sh method you can see that IDE recognizes that there is also this script returned STD out a variant of this SH method so let's use it we will set script to script and return STD out false this is the default value for SH step in engine gas pipeline and here let's implement the very naive a very simple way to execute processing shell so what we will do is we will take script I can make sure it's the string and then we can call execute method this method takes a string and executes the shell process then we can set weight for and then depending on the exit code if it's zero then if haromm return STD out then we will just return the output otherwise we will just print it and if there was an error we will print line text from the error of output and also let's and this so we can print line the comment that is executed here okay so let's run our example now and here you can see that those SH comments were executed so the first SH comment was just list files in the current folder you can see this is the output from the LS dash L a comment I also executed date comment to return my current date and I also executed maven - version comment here this is really nice now we are almost done here but let's say that we don't want to use those environment variables so let's say I will add echo some string and I will do it a little bit differently than it is done in Jenkins pipeline let's say I want to inject this end variable to this steps closure okay how we can do this let's get back to our pipeline DSL so here we have our environment and we need to inject it two steps closure which is executed here so we will add we can just add this environment variables here but there is one thing this parameter is not recognized at the moment and we can fix this we can add closure param sanitation which is instruction for a compiler what parameters Disclosure expects so in our case we will use simple type signature and there is this options array I will just I will use a single option for accepted parameters which is Java util map and now as you can see this and the variable is automatically recognized as map because this is the signature from here and now I can access this some string with code completion from the IDE let's run our pipeline and we can see this some string with the full bar variable was printed correctly using our echo step and now you may think that okay works because groovy is like a dynamic language there is probably some dynamic magic going on under the hood let me show you one thing because of course we were running this in groovy interpreter using dynamic compilation but let me show you what happens if I turn static compilation in the groove interpreter everything works exactly the same so it's not that this DSL is possible only because there is some dynamic method invocation magic going on you can use the same features with static compilation and what does it mean and this is really important it means that if we want we could write this DSL implementation in Java because all you have to do in this case is if you add groovy dependency so your Java program recognizes those delegates to closure params and other things then you can implement DSL in plain Java and then use it with any improvy script so that's all for today I hope you have learned something interesting from this video and if you want to run this example on your own computer there is a link to github repository in the description my good friend vladimir orany wrote an excellent series on groovy dsl builders if you want more I strongly encourage you to go and check his blog post series and in the meantime see you in the next video [Music]
Info
Channel: Szymon Stepniak
Views: 36,381
Rating: undefined out of 5
Keywords: groovy dsl, groovy dsl quickstart, groovy pipeline dsl, groovy dsl how to, groovy dsl introduction, groovy java dsl, groovy jenkins pipeline dsl, groovy dsl builder, groovy programming tutorial, groovy programming dsl, groovy dsl jenkins, groovy java, szymon stepniak, eprintstacktrace, learn groovy, learn groovy dsl, learn groovy script, how to learn groovy, dsl groovy, learning groovy, groovy for beginners, groovy quickstart, groovylang, groovy tutorial
Id: i9pNYW1Pg9A
Channel Id: undefined
Length: 23min 1sec (1381 seconds)
Published: Wed Apr 08 2020
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.