 into the cloud. Welcome. It is the 19th, in your time zone, yes, still the 19th of June. And it is, this is Google Summer of Code, Get Cash Maintenance. Thanks for your cash for being here. Let's go ahead. Okay, what are the topics you'd like to discuss? Okay, I have written can you like share your screen so that you know, you can open the project and yeah, I'll show you the status. Okay, so here's, here is the screen where I was actually doing some further manipulating. Is this the screen you want? What would you like to see? Do you want to see? Can you run the project? Sure, you bet. So here we go. Let's bring up this one. So you want to you want to run it with a with a local Jenkins. Yeah. Okay, great. Yes, absolutely. Jenkins. And if I remember right, you've got it already configured to run with Jenkins 2.346. And we'll need a web browser, won't we? So let's get a web browser. And eventually it will come up and localhost 8080 slash Jenkins, I think. Ah, I was right. Good. Okay. So I worked on the scheduling part, you know, scheduling maintenance tasks and adding it into a queue. But I'm not sure that is, you know, like the code is written the code for it. Can you like once go through it so that you know to confirm if it is the right way or not? Let's go through it together. That's a great, great plan. So you can now enter the crown syntax. So like just enter the crown syntax, you know, for every minute so that we can test it. Oh, every minute. Okay. Yeah. Okay. So we're going to incremental repack every minute. And we're going to, yes, I meant it. Let that be. Yeah. And I'm going to GC weekly. And whoops, weekly. And I'm going to do commit grab prefetch daily. And okay, so now I'm going to save that. Oh, wait, I don't know about like, can you write it like at the weekly kind of thing? I'm sorry, can I do what? Can you write a given input as accurate weekly? Does it take our Jenkins? It should that that's that is allowed crown syntax elsewhere. So I don't know if it's allowed crown syntax in in in the parser you're using, but it's definitely allowed crown syntax here. So for instance, let's create a new job on scheduled. And we're going to do a freestyle project. Come on. You can do it. Okay, so we want to build periodically. And now when we look at this, the help it will tell us things like, oh, come on, where is it somewhere in here is the hint of the other allowed syntax. Oh, now that's interesting. I'm just sure that it was allowing daily. Just a minute. Oh, here it is hitters. In addition, at yearly annually, these okay, so let's try those. So we're going to say it's going to execute yearly, annually, monthly, weekly, daily, midnight, and hourly. And now what does that tell us? Did it give us an okay, I need to close the help now. Don't I? Okay, and it says, yes, this would have run. So next run would be at Sunday, June 19, 701. Ah, so it will run very soon within about an hour. So I don't know why it's throwing an error on my team, because I didn't write that yearly, annually then. So I'll have to check that out. Well, and it may not throw an error. Let's take a look. Let's see what, because I think you had a, what if we say here that, so let's say hourly. Save, save, save. Oh, you have to save it first. It's throwing an error in the building. Oh, interesting. Okay. All right. So, so there's, so that's, we learned something. The, the, the syntax that you're using is, or the checker you're using is not allowing the same syntax that Jenkins users are accustomed to elsewhere. I'll have to check that out. Oh, but even, even now it's saying invalid. No, no, there are other, there are other weekly hourly rates. Oh, right. I see what you're saying. Yes. I need to make it valid. So let's do it. Let's here, let's back here to, let me grab some other examples that, that are available there. And we'll, we'll paste a few actual valid examples. Oops, wrong one. So here, cron scheduled, configure. Let's go read the help. Okay. So the app, the at sign-based ones did not. Let's try some other examples like these. Ah, that's not, let's give myself a cup of or where I can copy those things. Okay. So we're going to do every 15 minutes. And this one, we're actually going to do it because you had advised, we're going to do it every one minute. Now this one, every, there we go. Okay. Every 45 minutes. And this one, and this one. Okay. Shall we try it? Yeah. Okay. And that, and that was accepted. Good. Okay. Now, and I don't remember if this is actually an every minute syntax or not. So, but So now the data has been saved internally. Like if you go to that folder, right? And with the workspace folder in your ID, you'll find the file there, the XML file. Okay. So you want me to look inside? Actually, I, it's easier for me if I just use my bio browser. Okay. So here you want me to go to the, this thing to hub, my plugins, git plugin, work, and then there's the git maintenance Jenkins plugin, the XML file. Okay. Okay. So let's drag that into our friendly local editor. Okay, here we go. So here the data is stored internally. Okay. Now if you, you know, like switch, you know, terminate Jenkins and run it again, the data is loaded from this file. You can try that out also. That's also working. Okay. Good. Very good. All right. So, so if for instance, I do, where is my Jenkins? My Jenkins is right here. If I do a slash restart. Flash restarted. Oh, it won't let me restart. Okay. So if I bring up this thing and hit the enter key and of course it's windows. So it says there's a busy file. So I have to interrupt it and run it again. So now all the configuration is loaded from this file. So that's what I worked on. Oh, good. Right. So what you're showing is what you've shown now is you have successfully persisted the definition and it's, it's, it's coming back after the very good. Okay. So let's see that. So let's go manage Jenkins. Oops. Come on. Respond. Here we go. Patience. Clearly I need a faster computer. Or maybe I just need to do less stuff with my computer. Okay. Manage Jenkins and get maintenance. And there it is. Yeah. Okay. So now in terms of tracking the tracking the little things like the weekly, annually, etc. You'll do that somehow. I'll do that. Yeah, I'll do that. Okay. Because that way we avoid the overhead of issue reports in Jira. I don't think they'll help you move as quickly as you can. Great. Okay. Yeah. Yeah. I look into that. That's not a problem. Great. So now can you like schedule one job for like every minute kind of thing? So incremental repack I think is actually scheduled for every minute. Let's be absolutely sure and do a save. And then click on execute. Okay. Execute. So now, now after a minute you'll see the, you know, in the terminal and the terminal you'll see a queue being printed. Okay. Good. You'll have to wait for a minute. So exactly like 614 your time will get printed on the screen. Good. All right. Well, so then let me, are you okay? Well, there we go. Okay. Yeah. So this task has been scheduled for execution right now. Okay. The code for it is written as in the, you know, in the task scheduler file. So the cron, yeah, there. So basically if you open the cron file, the cron file, okay. This file, if you see the code there, the get recurrence period, this thing is said to run every minute. Okay. And every minute with the function called schedule maintenance task is run. Okay. Which, which checks the cron syntax whether it's valid or not. And then if it's valid, it's added to the maintenance queue. Okay. And there's not already something in Jenkins that would do this for us. This was something you had to create on your own. So there wasn't, there isn't already a scheduler facility inside Jenkins. That surprises me. It may be there. I'm not sure because when I explored, I found this part if there is another part, we could follow that. Okay. All right. Good. Yeah. So, so you're open to other. And if we find, if we find another way to do it, great. Okay. Okay. And then if you go to the task, you know, task scheduler class, there you'll, you'll, here you can see the schedule task. It checks all the configuration whether, you know, this maintenance task is valid or not. If it is valid, it's added to the queue. Okay. Here I had a doubt. Okay. I created a new thread in Jenkins using, you know, the runnable class. Okay. That's logic. Is there a prebuilt way of creating a thread or can I use, you know, the Java thread to create a thread? As far as I know, you can use the Java thread to create a thread. I'd have to look at other examples to be sure, but I don't see any reason not to use a new thread. Let's, let's do some checking elsewhere. Let's see what is, what is something that, ah, the global build discarder, as it would be my example. I assume you had looked at it. Was it using new thread to construct the thread? No, no, no. I don't think it was using a thread. It used to call the build function and that used to internally do it. So I don't know how. Oh, well, so if, so it was using a build, huh? Interesting. Okay. All right. Well, let's, okay. So global build discarder. What I'm doing is looking at, okay, build the starter. So in GitHub, and now what it's got is, this is the strategy. Where is the implementation? What does that? Oh, I think that's present in Jenkins. Oh, is it, it, build discarder is part of Jenkins. Global build discarders part of Jenkins core, isn't it? Yeah, yeah, yeah. I'm looking in the wrong place. Thank you. Okay. So let's look at core. Now I don't find it. That's not attic sensible background build discarder. Here we go. Okay. This is Daniel's poll. It's been merged and here's what changed. Okay. So background global build discarder, which is an async periodic work has, has an execute method and a process job. Oh, so what it's doing is it's iterating over each job and calling process job on each job. Okay. Okay. So this is his global build discard background global build discarder. I think this uses an async, yeah, async periodic work. The reason, yeah, so async periodic work creates a new thread which runs asynchronously. The reason I was more preferred towards periodic work is because there's a timer thread in Jenkins, which, you know, every, you know, based on that, the recurrence, you know, function, it runs periodically. So I was thinking if I use a periodic work, the amount of work, you know, a task that a thread has to do is very less. So I was thinking we don't have to create another thread was what I was thinking. Okay. And I, I don't have anything to disagree with your logic. So that, that, that sounds reasonable to me. And exploring it and experimenting with it feels like the best way to decide if it should be periodic work or async periodic work. The logic would be the same. It's only about whether we are going to create a new thread or use the same thread. Great. Yeah. Okay. Oh, oh, this is, this is a reminder. We need to be sure we've got a symbol. Good. Okay. And what exactly is a symbol? What a symbol does is this allows us to use, to refer to a capability in Jenkins by a shorthand notation, in this case, build the scarters and build the scarters then is, can be put into a configuration as code definition file and used to define the settings for something so that when Jenkins restarts, the settings or when a brand new Jenkins is, is created is, is being spun up. I can have the definition already that hey, these are the things I want as my global configuration. That's actually a good one for me to check separately if, yeah, it's, this is, that is a good feature. We should be sure that we include the cheering you include in the plugin that it can be configured by configuration as code. So very good. All right. So sorry, I was, I was, I'm not being as helpful here as I should be your crew. The question that led us to this was you wanted to, to decide should we use help take me back to what the question was, you know, the Java thread or should we use a better thread in, you know, where I have to create a thread in Jenkins and link it to something so that we do the work or should I, can I create a Java thread? So I don't object to your creating a Java thread. I'm just a little surprised to see that Daniel was able to do global build discard or without creating a thread. So is that because he used async periodic work instead of using periodic work? Oh, I even, I thought of creating, like if you go back to that code, okay, which I've written, if you, you know, the reason why I, I could have created, you know, run the maintenance task in this function itself. But the reason I chose not to do it and create a new thread is assume if the maintenance tasks, a task, you know, to execution takes a lot of time, like an hour or like 30 minutes or so, then this thread would get blocked, you know, to just run that maintenance task. And, you know, this thread again wouldn't run the next minute because it would be busy doing something else. And that makes sense if it's important that we must, that this thing must run every minute. My thought was, isn't, oh, no, no, okay, right, because background, so the global build discarder is not, is not allowed to be defined how frequently it checks, right? This thing, this thing is different in that way in that it will, it will, okay, for instance, yeah, what it's defined is it will run and not more than once an hour. Yeah. Okay, all right. So you're saying here what you've got to do is you have to be sure that the task scheduler gets invoked more frequently and therefore a thread is, is the best choice as a way to, to, to start a separate thread of execution and not disrupt this one. Okay. Not block this one. And that, that seems reasonable to me. I don't have experience in this part of Jenkins, so I can't, I can't promise you that you won't later discover Mark Waite was absolutely wrong. Okay. So that was a big confusion, like, you know, should I create a thread or do I use async periodic work or periodic work? That was one thing I wanted to ask. So basically now this thread will have the functionalities of executing the maintenance task. Okay. So that's what is the functionality of this thread. Yeah. And now, so this thread is then going to execute the maintenance task. And is there, do you already have safeguards in place to prevent a create an explosion of threads? Say, yeah, yeah, yeah, I have, I have that thing. I've added it in a statement. Like if it's alive, then you don't add it. Okay, don't create a thread. So, I see. So this here is the safeguard says, hey, if something's already running, then do not create a new another thread. So this is that's how you'll defend against an explosion of threads. Okay. Yeah. Right. And this, this data's report here that you're using for diagnostics, that's reporting the state of this task executor. Yeah. And it could be that in the time between here and here, it may have finished. And if it did, it will say, okay, it's no longer alive. But it at least reports the reality. Good. So, and the thread wouldn't even be created if though, if there are no tasks in the queue, because it wouldn't make sense, right? So I added another safeguard and in the, if like the maintenance queue dot is empty. So if the, you know, maintenance tasks, if there are no tasks to execute it, so there's no use of creating the threat. So that was also added. Right. Okay. Good. Now. Yeah. So now inside this task executor, you know, thread. So I was thinking now, you know, we discussed about getting the reports, but you know, part of the, you know, get cash is present on the Jenkins controller. So for that, I would, you know, need, so we have discussed, like, there's a get SCM class from which I can get the, what do you tell, part of the caches, but that gives me only one, what do you tell, a path. Okay. And to get that path also, I need to pass the URL of the repository. And how do I get the URL of all the repositories? Is there any way in general? May, we may have to, we may have to extend the get client to give you that information or extend something to give you that information. If it's get client or that's perfectly okay. Right now, you're saying that the, the only access method that there is to the list of caches is indexed by, by URL. Is that right? Yeah. Yeah. So then I would think what we need to do is, is add another method that lets you ask for, let you iterate the list. Yes. Okay. So shall we, shall we open it up and look at that together? Would you prefer to explore it on your own? Yeah, yeah. No, no, I wanted to see how that thing goes. Okay. So let's go looking together and let's look and get client plug in. Before I do that, let me be sure that just a minute, it'll be just moments while I, I need to get my condition set up before I bother to open it, cancel, give me another bash shell. Okay. Okay. So let me get that ready to go just a moment. Okay. So here we go. All right. I just had to see if I had any in progress work that I couldn't show on a recording. All right. All right. So let me get rid of that branch. Pull. Okay. Now. Okay. Now let's open it and we'll go do some looking. Okay. So what we're trying to find is the things that are related to the caches that are involved in see what might be a way that we could find that we could look for the word cash. Check out change law. Okay. It's gotta be. See, I, okay. Oh, unsupported command. So it must be either inside get client or inside CLI get. I thought it would be in the login itself because that client was only for execution. Right. Right. So let's go look there. Very good. Okay. So let's look here. There's a get SCM. Good. Okay. So let's go looking in get SCM, looking at the methods on get SCM. Where would I find those caches? Well, hang on just a minute while I do some other searching, let's do it this way. Okay. So abstract get SCM source, there it is has a cash directory. Okay. So, okay. Here we go. So the thing that holds the caches is abstract get SCM source. So we can certainly look here. Oh, that and that there's a, I think there's a method to get a cache for that you need the UR. So, great. So let's look. And so get cash entry get. Yes, here we go. So get cash, dir and the cash entry that it's looking for is the remote. Okay. Good. So what I assume you're going to have to do is add in abstract get SCM add another method that lets you iterate over all the caches. Yeah. So for that I need the URs. And you know, is there a way to get all the URs like all the remote? Actually, I don't think you need. So I would, I think what you want to do is all right. So notice here that there's this thing that looks at Jenkins dot get root there are caches. So this is the directory where the caches are stored. Okay. Okay. So then I don't even need this function. Right. So I can directly use that path. Well, what, what I think you would want is you want, I think we want to keep all knowledge of where is the cash stored, etc. inside abstract get SCM source. And so you would want to create a method in abstract get SCM source that lets you iterate over the caches. Can you repeat like I think you want to create a method here in abstract get SCM source that lets you iterate over the list of caches. Okay. Okay. So that, you know, I get all the, you know, you know, caches present on the Jenkins controller. Right. Well, and so that, so that you're not, you're not spreading the knowledge of where are the caches or how are the caches managed beyond this class, because for instance, it's got, it's got a locking mechanism, right. And, and some of the operations you're doing, like garbage collection may need to take a lock. And so, so it may be that you, you want absolutely to, while iterating, you may say, okay, give me, let's, let's walk through the list of caches. And on each cache, you want to get a lock on that cache optionally. Another, wait, I have a doubt here. Why would we need a lock, like in the sense like how would a lock be useful? Or how would it help us? My thought was that I'm not sure that you want concurrent access to the cache by other parts of Jenkins while you're running garbage collection. Okay. Okay. So basically you're like, you're saying that, you know, there can be other plugins which may be using this cache. And when I am running a GC, it shouldn't, you know, those plugins, you know, shouldn't access this cache. Is that what you're saying? Yeah, that's, that's at least the concept that because Git has its own concurrency defenses. It really has its own concurrency defenses. However, its concurrency defenses are based usually on command line Git being the only thing that operates on that repository. And in our environment, we allow either command line Git or JGit to access a repository. And so my thinking was you may need to apply a lock for operations that you know are not, what might you say, that are prone to problems if there's concurrent access. Now, my understanding prefetch, for example, should not have any problem with concurrent access. You should be allowed to do prefetch without disrupting anyone, at least based on the, I think that's what we learned from reading the Gitman pages in project proposal phase, right? Yeah. Okay. So then we'll have to think about what would be needing it. So I think a GC would need it. I don't know, I'll have to explore that part, whether which one needs a cache and which one needs a lock and which one doesn't. Right. And I think you just said it very well that you'll need to explore which things do need to be locked and which things don't, because some of the operations should not require locking. Yeah. So that makes sense. I think I'll, so basically I'll add a method in this, which you know, iterates through all the caches. Okay. And you know, give me the path of that cache and no, and add a lock to it, like based on the condition so that I can learn the maintenance task. Good. Yeah, that sounds good to me. So yeah, that was something on the list. And then, okay, then I had another doubt regarding, you know, the test, can you, or go to a task scheduler test? Sure. That's so task scheduler test. Yeah. All right, so test packages, task scheduler test. Here, this one. Okay. Yeah, I wrote this function which fails one on one, because you know, I'm not able to test this function. Okay. So now I'll be needing a key. How do I, you know, fake a situation where I'm scheduling maintenance tasks? Yeah, so I think, so if you're okay, let's play with a little bit together. Is that all right? Yeah. Okay. So what I would do is I would open up task scheduler here. And at least in my IDE, it's got an option that I can right click tools, create update tests, and it will construct skeletons of the tests for me. Okay. So what it said was, and so it's inserted, the green blocks here are insertions that it made. So it says tests, it's added one new test, schedule tasks. So let's call that. And let's see. So we've got task scheduler, is this, and then we're going to say task scheduler.schedule tasks. Okay. So that now, and it turns out, we don't, we didn't need, although maybe let's take advantage, well, it's since it did this for us, I'm going to do it like this, because we're going to need a task scheduler on every single method, right? Yeah. Okay. And oh, I see. You had already had this test. These are the same tests. Yeah. Okay. Right. Because this one, you were just doing a trivial, do something, so I can assert something. Yeah. Okay. So now the question is, how do we, what are the externally visible things that schedule tasks can do that we could assert? Because the maintenance task present in that class would be private. Okay. So. Right. Yeah. And then any other fields also, I think mostly would be private. So, and I wouldn't want a method, you know, which returns the maintenance task. Okay. So let's, well, so let's, let's take, let's take a look and see what, what we could do. So let's go look at your source code. All right. So here we've got schedule tasks. So one, I guess one option, I see that you've got check is task in queue, but you've made it private. Yeah. We could make it package protected and use it to check that a task has been queued, but not make it part of the public API, just make it package protected for test purposes. Okay. Is this one that you've seen that you'll need to use elsewhere? Oh, you're already using it here. Right. So yes. So, so testing, testing that would probably be a good thing. And so at least a technique I've used elsewhere in the get plugin is say something like this package protected for test for use by tests. And then I take the private off of it. And now I can call it from my test class and, and see, Hey, is this the, Oh, good. And you showed me how to do the streaming thing. Nice. Yes. So nice use of a Lambda. Very good. So, so then if we go back here to task executor tests, oh, not tasks, sorry, task scheduler tests, this one. And, and again, I'm cheating. I'm going to use my, my IDE and let it generate the methods. So it says, Oh, check is task in queue. And I'm pretty sure that whatever IDE you're using likely has the same facility, you may want to look for it because having somebody else generate your test prototypes, at least for me is a real help. It reminds me, Oh, I should have a test for that method and that method. Yeah. Okay. So here, we're going to use task scheduler instead of instance. Okay. Now we need a real task. And that, of course, is the wrong constructor. So you'll, I think you'll have to pass a task type and then yeah. Oh, good. Right. Okay. So we're going to take a task type dot. I want to do prefetch. Yes. Excellent choice. Okay. So now, and I don't need to use the expected result thing. And I much prefer and, and I have to just acknowledge I like what's called ham crest exceptions, where we stated as assert that, okay, this one is a Boolean. So maybe that's a bad choice assert true that. Oh, but you're okay. But then first I need to create a maintain like, you know, have to add it to the median and subscribe. Yeah. Good point. So all right, let's, let's do the, let's do the, let's do something different. Let's do it like this. Right. With that. I think yeah. Okay. So we don't need to call this at all. So I've gone a little longer than I wanted to in terms of not having run this yet. Let me execute this and watch what happens just a minute. And my IDE has some configuration issues right now. So I need to go into my ID, into my command line and recompile. So the whole point of asking this question is, do I have to test every method I can or like, because some, some things are like, I don't know how do you test them if get this guy, you know, the logic to test them. Yeah. And usually, usually if you don't know how to write the automated test, it's a good hint that the logic of the thing may be too complicated. And you need to split it out so that it becomes testable components. Okay. So for example, the, for me, I, and others have different approaches, but for me, I prefer to test with automation as much as I possibly can. So that when I make changes later, I get caught by my tests if I made a mistake. Yeah. So I think I just build this function into multiples of functions kind of thing. That was, that was my assumption so that you could, so that you can test it. Now, if you, if while writing the test, you realize, oh, I can test this with the following easy steps, just write the test then. But if, if you find, oh, well, I'm having difficulty, for instance, oftentimes I may find it difficult to get to something like that. And when I find that, I, I will typically then say, oh, what do I need to do to make that so I can reach it with a test? And it package protected is one of those techniques, right? This technique is, why did I make it package protected? Only so that I could test it. There was no other reason to accept to make it so I could reach it with a test. Because then I don't have to, when, when future releases are happening, I can, I can rely on the test to help me without having to interactively check everything. Yeah, makes sense. So I, I think I'll have to go through this again, you know, try to split it into functions and check whether I can test it or try testing it again. Great. Well, and I wanted to, to, let's see there. I was, I was in the middle of experimenting with one of your other, other things, task executor, doing that same technique. Yeah, no, what I'm saying is I had done the same thing with task executor that we were just describing with task scheduler of trying to add tests for each of the methods that's exposed in the API and then use that to explore the implementation more, more thoroughly. Yeah. Okay, so this one, we say, J unit version three, right? No, no, this is J unit four. This is definitely four. Okay. Now it's not J unit five. And, and the reason it's not J unit five is this syntax right here, this Jenkins rule thing is not available in J unit five. They, they considered rules to be a something they eventually removed from J, they, they removed when they made the transition to J unit four or J unit five. But Jenkins rule is crucial here, because it's the thing. I think that would be a breaking change, right, if you do it to unit version five. Right. So, well, and, and I've used, I've used J unit five in other projects, in other Jenkins plug-ins, but you can't use J unit five with a Jenkins rule. There isn't a Jenkins rule, a J unit five compatible Jenkins rule yet. Okay. So, so this here you, you're stuck with J unit four. But this one, this one I had to, I think this may have been the one that I had to add J, Jenkins rule to it in order to get it to pass. If you're okay, let's go look and see. Nope, it still didn't pass. All right. So here's, I had, I had pushed to your branch. A change, let's see if, let's see if my change arrived. Use Jenkins rule in task schedule test. Okay. It did arrive, but all the tests did not pass. You're okay if we spend just a minute finding out why. Yeah. A task, task, oh, task test. So the one I changed seems to now, now be passing. Now, if we look at the test history, there it, no, is that right? Okay. If I look at the test history graph, it shows number 17 failed five, number 16 failed three. I actually have more failures, not less. Well, that's terrible, Hrushakesh. Okay. So what did I do wrong? Latest test result shows task, task test is failing. Okay. So why was it passing on the previous build? I don't know what I broke on task test. It's, it's a different failure. So interesting. Task scheduler test was failing. So it's fixed. So, so I succeeded in fixing that. But now we've got a failing test in task test. Okay. So, so if you want, we could go look at that together, or are there other things that are more valuable to you? Okay. Before that, I have a few things. I have a few things. If you finish off with that, then yeah. So there's this thing about form validation. Okay. So like, as you've seen, I once you submit a wrong, wrong, you know, cron syntax kind of a thing. It doesn't, it doesn't let you submit the form. It throws an error on the terminal. Right. So I wanted to show notifications and all those things, you know, but I'm not able to use that design library's notifications. And this, because once I submit the form, I'll get a response from the client and this page would be loaded again. Right. So how do I add a notification to show key to show on the screen that there's an error or something like that? Okay. So let's, let's, let's experiment with that for a little bit and see if we can find something that's already doing that kind of thing for us. You know, something after I submit the form and then there's an error and then it shows. Okay. So, so, so after submitting the form, not while, while working with the form, I would think you want it while working with the form, don't you? You want to check it even before they submit the form. Yeah. But then I'm not able to like, but then assume once they, you know, enter all the details, you know, all the crown syntax data and then they click the submit button or the save button. So there is eventually going to be a request sent to the backend. Right. So I was thinking in that sense. So, so when the request request is sent to the backend, what I'm not sure what you're envisioning, we would tell them. So take me through that again. Let's, so I'm on the get maintenance page and here I've entered a definition. Now I press save. Yeah. So now if you enter a wrong syntax, like can you enter a wrong syntax in any of those? Sure. So let's put here. Yeah. And then now I click save. Okay. Even though this error is being displayed, assume the administrator saves it. Okay. Yeah. Okay. So, so if, if the administrator presses save with, with invalid input here, what are we going to do with it? I think that's your question. Yes. So, so here when I click save in the terminal, it's showing it's, there's a, it's displaying that there's an right. It says here invalid, invalid prawn syntax. Right. So now I have to, you know, so basically what am I doing? I'm read. I have to redirect it back to this page, but then I want to use that notification to show the notification on the screen. So. Ah, right. Okay. So let's, let's see if we can find, find an example like that. So the idea is you want a way to, because if you just return them to this page, if when they press save, they just came back to this page, wouldn't that already be enough? But, but then we'll then like, how will the administrator know like there's an error? Like, he would he just look at it or would they look at it or. Good, good question. So then maybe to improve the experience, what you're saying is after the save come back, you would like to mutate this page. Swear it says has a big dialogue at the top that says you have invalid syntax on this page. Yeah. Right. Okay. So let's, yes. And let's, let's see what we can do with that. So let's, let's see if there's some other examples of ways that's handled. So if I look at, let's try, well, here, let's, let's try it. Here's, here's one. We're going to enter an invalid URL for a Git repository. We're going to say rsync. Okay. So that's what it did. It just changed and said, hey, it tried the operation and stayed on the page. Okay. And if I save this, is there anything like village from saving? It does. There's nothing that stops you from saving it. It just says, hey, that's bogus. Okay. Because why I am trying to do this is because assume if I don't, if I save this internally, you know, around cross attack, there'll be so many errors being thrown in different places. Whenever I try to use that cross syntax, and whenever I'm trying to execute it, there would be errors, which will, you know, so many errors, which would, so, you know, which will be thrown. So I was thinking if I stop it initially only, you know, prevent entering around cross syntax and saving it, then I wouldn't have to check it anywhere, you know, and, and I wish that were the case. But the reality is because you'll be supporting configuration as code, the administrator could by configuration as code give you a completely invalid syntax as well. So I think I think you have to check syntax everywhere. You have to send check syntax at, at any location that accepts the syntax, right? So, so you So basically I'm checking the cross syntax at two places, one when he's when they are entering the data into the input field, and one where when they are submitting the data, you know, when they are submitting to store it internally, those are the two places I'm checking. So if, you know, so basically when you're saying as configuration in configuration as code, and can this enter, you know, like cross syntaxes, can this send it to us? Like, can they enter it? Yeah. So well, so let's I think, I think I can show you an example of a configuration as code defined just a minute. Let's, let's see if I've got one. I think I do. So here is, is that, is that text readable for you? Okay, so if we look at, I suspect that, let's see, get branch. Okay, good. So we've got ref config. So this is, this is a Jenkins installation that I maintain with configuration as code. And here are the definition files. Let's see if we can find one that has a Cron syntax in it. There we go. Ah, that's good. Nope, nope, that didn't help. Okay. Oh, so there aren't any here. Okay, let's see, where would I find a Cron? Oh, oh, no, no, that's, that's not okay. So let me do some continued looking here. Oh, I know what where we can do is, no, is there a thing in global configuration that has a schedule defined? Configure system just a minute. Okay, schedule, fair, the priority sorter. Oh, yes, here we go. Maven scheduled, oh, this is a terrible example, but all right, Maven scheduled repository cleaner. It does not support configuration as code. So that won't help me. Let's see. So, so I apologize. I don't have a configuration as code example that would show it in context. I can, I could attempt to create one, find a plugin that does configuration as code and takes Cron syntax and, and make sure that I can share that example with you the next time we meet. Yeah, sure. I think that would Okay, good. Yeah. So, because when I let's see, well, maybe actually, maybe, maybe there is some, okay, this is mostly agent definitions. And this is the read me. Okay. And this is the security config. And these are tools and the tools certainly don't need scheduling syntax. Okay, unclassified seems like a really likely one to have it. Just a minute, Roushakesh, if you can stand for me to look for just a little bit in case we can find an example priority. Nope. Sorry. Okay, I don't have a good example of, of a configuration as code setup that includes Cron syntax. No worries. So about the architecture of the form submission. So would you like, how would I proceed with that is what I wanted to move. So do you want, yeah, do we want the error being displayed like a notification or is this fine? I think, I think for now, just, just display it here and accept that whatever data they stored, we will put there, even if it's invalid input. Okay, but I think that would cause a lot of, so basically what exactly is happening right now, if you enter a wrong invalid Cron syntax and click save, right? It's just going to throw the, you know, error in the terminal, but it doesn't storing internally. So if you go to that work file, no, there's nothing present there. So all this new data hasn't been saved. So that would, you know, prevent us from having any problems anywhere, you know, somewhere else whenever I'm reading the Cron syntax. Yeah. So, well, okay, let's see. So, so I think there must be, there must be a way to do what you're suggesting. So let's, maybe we can find another example that will let us, because what, what I think what you're saying is it will be much better for the user. If we, for certain classes of mistakes, we tell them you're not, I did not even save what you, what you asked for because it is so broken that I didn't save it. So let's, let's take a look at this and see, see if we can find some examples of a case where something is so broken that we refuse to store it. If you think of it in that way, it would be easier for us also to implement it because if we store an invalid, you know, Cron syntax, then whenever we read it to execute it, we have to keep checking whether that syntax is correct or not. Whereas before only when he's, when they submit the form, if we check it, you know, it'll be a very good safeguard was what I was thinking. Yeah, just, I'm not, I'm not sure that, that your, your desire to not have to check it as far as I can tell, you'll get input from users. And anytime you get input from a user, you've got to check is it valid syntax, don't you? Yeah. Oh, can you repeat what you said? And so anywhere that the code could receive data from a user, you have to check that the data from the user is valid, I think. Yeah, that, that I'm doing it. Okay. And that is storing it in the file. Okay. And, but do, do I have to check it when I'm reading it from the file as well? I think so, because, because, well, I would think that if you don't check it from the user, then you might have people like me who store their XML files into a source control system and change the XML files themselves. Oh, okay, make sense. Okay. And I say people like me, because I am exactly one of those people who does, who does exactly that. And I, I sometimes store my XML files because they're, they're readable data files, I can use them and make them do things that I want. Okay. So, okay, that could be an issue then. So whenever I have to read or whenever I'm executing, I'll have to check the, you know, whether the crown syntax is valid or not. Right. I think so anyway. So let's, let's test. Okay, here we've got a malformed URL reference. It's still malformed. If I save it, it allowed me to save it. And what did it do with it? It, it retained it. So, so it, so the, the general pattern seems to be use, take whatever the user gives us, show them a warning in this red text, but don't reject, don't discard their, their input, even if it's, even if it's wrong. Yeah. Okay. So I think I'll follow that pattern then. All right. Do you, since the two of us are still here, do you have other questions? I guess one question for me to you, are you okay? If I, as a matter of personal pride, go find out how I broke more tests, attempt to, attempt to make changes. Are you okay if I push changes to your code to, to fix that? Yeah, it's fine. I have still two more questions. Okay. I know it's going to be late. Yeah, but it's fine. So two more questions. One thing is I added permissions to that jelly fine. Okay. So, you know, for, so that administrators only can use it. But I don't know whether it's working or not. Okay. I think administrator is by default true or something whenever I'm developing the plugin. So I'm not sure whether, you know, is it only for administrators or are everyone able to use it or not? Well, and so let's try it. Let's first, let's first enable security. Okay. So what I just did was I enabled security. I'm now going to sign up. Okay. So, and it says my password is only moderate strength, nonsense. That's a very good password. Okay. So I just created myself an account. And so now I am an administrator. So first check, I can do get maintenance. There it is. All right. Now I'm going to log out, manage Jenkins, get maintenance. Let's fix the mistake I made save. Did it save? And yeah, it saved in the domain. So as far as I can tell, it did save. So I think that since I am not logged in, let's see if I can let me check. Maybe I've got wrong permissions. Let's check the security configuration because it may be that I've got it. Okay. Authorization is currently, anyone can do anything. Let's change it to log in users can do anything. Okay. So now I'm logged in. As a logged in user, I'm going to change this to 42. Oops. 42 is the wrong value. So I'm going to change it to six. Save. Okay. So now I'm going to log out. And now, oh, see, look at this. It's already proving that it notice manage Jenkins isn't even there anymore. Okay. So just a minute. Now I've got to find the URL to manage Jenkins so that I can, so that I can check that it, okay. So this is the URL that I need. Okay. Remember that URL. Okay. Going to log out. Now I'm going to enter that URL. And hit says, uh-uh. So I don't know if it's your security checks or someone else's, but security checks have blocked me from doing that. Because I've added the permissions, but I wasn't able to test it. So I don't know. Well, and so did you, based on what I just showed you, are you comfortable now that you know how to do the configuration to test it? Yes. Yeah. I'll try it once again. Okay. So just to replay one more time what I did. What I did was I went into configure global security. Okay. And I'll try to post the recording of this really quickly so that you can look at the recording. Then in security realm, it defaulted to none. I said use Jenkins own user database. And I intentionally allow users to sign up because initially there's no user defined. And with no user defined, I would be locked out and have nothing I could do. So I allowed users to sign up. Now I can, having done that, then I also changed instead of authorization, anyone can do anything, make logged in users can do anything. Now, if you wanted to get even more sophisticated, there are other techniques, but for me, logged in users can do anything already shows the example. So did that help? Yes, yes, yes. That helped me. All right. You said there were, were there other questions that we need to Last question was regarding the size of the pull request or whatever. Oh, yes. Oh, yes. Absolutely. Particularly in this, in this mode that we're in right now, right? The mode we're in right now is you need to be able to rapidly explore and experiment with things. And you need to commit something and realize, oh, that failed, commit something else. Oh, that failed. And it doesn't matter. You just keep doing that. And eventually we'll probably get to the point where we say, Hey, you've reached a point where this looks quite good. Is it time now to rework the pull request to become something you're ready to submit? And then you may, you may squash merge or you may, you may say, Hey, I want to rebase it. Or you may, you may say, I'm going to just take the contents of the files and create a whole new pull request that just says what I wanted to say. Oh, yeah. This, this very much. And I think, I think you've got it correctly noted already as a draft pull request, don't you? Yeah, yeah, it's a draft request. So, so that's already telling me and other maintainers don't merge this. So, so you're, you're just fine. The, the, the technique you're using works very well for me. I was, I was really grateful that you had done it that way because it allowed me to see, Oh, here are some failing tests. And I could see some of your thinking without having to have a meeting with you to talk about what you were seeing. Okay. So, yeah, okay. That, that, that, that's fine then. I'll go, I'll proceed with that, you know, method only. And again, once again, like the plan, like this Wednesday, the next meet, what I would be working on this, I'll create a, you know, a way to iterate through all the cash is present on the Jenkins controller. I would schedule the already scheduling is done. I'll try working on executing the maintenance tasks, you know, using the get client plugin, a basic version. So I think that, that is what I will be working on these two things. Excellent. That sounds great. Now, when are we, when are we next scheduled? Is that, let's see, tomorrow? Oh, two days. Okay, Wednesday, Wednesday. Okay. So if you, if we need to meet sooner than Wednesday, let me know. But, but congratulations on the progress you're already making on, on how things are going. Thank you. Anything else, Ruchakesh? One minute. I've written everything on the book. So great. I think, yeah, that's it. That's it from I think. Okay. All right. So and I still owe you the, how do we do online help for this? Because I want a question mark right over here. And the question mark. Yeah. It's one small thing. The button, can I put the terminate button beside the save button? I don't know. I feel that, that UI looks better, but I'm not able to do anything with that. In general, I don't think so. Well, let's see. Actually, let's, let's ask, that's a very fair question. I think there is, let's, let's look at the UI samples that are available, because in the design library, I thought that there were some buttons that we could see. So here's the buttons thing. All right. So this, no, that didn't help me. App bars. Yeah. Okay. So I think what you want is, well, maybe, yeah, maybe, maybe what you want to do is consider an app bar that goes at the top of the page where one says save and the other says temper says terminate or one says save. Where is that? Sorry. How embarrassing. Yeah. So one says save and the other says terminate or cancel. Now, now let's, let's see if how that, that might, there, I think there are things like that already in Jenkins that are consistent that way. Yes. Like the save and apply here. Okay. Right. So, so this kind of thing is, is certainly a valid, a valid technique, although I think this concept of the app bar may be better suited for what you're, you're wanting to do. I think the app bar would be on top, right? Right. Which, which for me is actually better, right? Because, because the, the, the user does some data and then they hit the bar at the top. Now, let's see if we got other examples in the maintenance tasks like configuration, configuration as code has a rather old UI. So this one definitely has two buttons side by side. So we could, I tried looking at its code and then I couldn't replicate the same thing on my side. So. Okay. All right. Okay. So, so you, you very wisely went looking for someone else who's done, done the same kind of thing. Good. Very good. Excellent. And this one has just the save and apply. Okay. So, so I think and managed plugins is a whole different user, user definition UI. So how about and this one just has save and apply. Well, should we ask a different question? Should this be save and apply? What does terminate mean? Oh, a dominate. Oh, yeah. Executor's to run and dominate is to, you know, stop running. Right. Okay. Okay. So execute, execute truly is, yeah. I think, see, for me, I think this belongs at an app bar up at the top. Where exactly would it come like on top on in the UI? Is it like beside the design? I think, I think it would appear. I think it would appear. It would, the way it would render would be like this where you would say maintenance tasks. And then there would be a button up here that says save and another one says execute or switches to become terminate. Okay. So I think, yeah, that looks better. I'll experiment with that as well. At least, yeah, by all means, try it and see what you think. You may say, no, Mark, this is totally unacceptable. But for me, the whole set of checks that you're doing here would actually be quite well suited by having a save, execute and terminate across the top for get maintenance tasks. Okay. I'll look into that once. All right. Any other questions? That's it. Okay. I think that covered it then. And thanks very much, Ruchikesh. I will try to get the recording uploaded within the next, I hope, 12 hours. It needs some time to get it processed. Thank you. I'm going to stop the recording now. Thank you.