BrandGhost

Copilot CLI to Fix My Busted C# Code!

In this video, we'll use the Copilot CLI to fix up some code in my product, BrandGhost, that is the result of some breaking API changes. We'll see how we can control the Copilot context and get some variations on solutions!
View Transcript
In this video, we're going to be looking at using the Copilot CLI to go fix up some issues that I have in a Nougat package that I've created. And if you haven't watched the previous video, I'll link it right up here so you can check that out. In that video, I walk through how I'm using clawed code as well as copilot CLI to go take my needler type registration assembly scanning nougat package that I have. It's all based on reflection and I had it migrate that to support source generation as well, which is super cool. I'm super excited about it. But of course, when I went to go finally integrate it after everything was done and I thought everything was perfect. Spoiler alert, it's not perfect. We're going to look at being able to fix up things sort of the same way that I was building it out. So, we're going to go to Copilot CLI. I'm going to give it some code examples and we're going to see how it can do in terms of fixing up some of the patterns that I have. If we jump over to get extensions, you can see on my screen just to give you a little bit of context. Everything that's highlighted in blue is what I was coding with Claude Code and Copilot, mostly Cop-lot CLI over the past couple days. And that's because I ran out of my limits on Claude. And my point in showing you all of this is not to say, "Oh, look, you know, AI is amazing. It's a million lines of code or it's a million commits." It's it's nothing like that. It's just to show you that I was in fact working on this. There's, you know, the the timestamps and stuff are over the past 48 hours, maybe a little bit longer. And so I was able to work with both of these LLM tools to go from a reflection-based solution over to source generation. The reality is that by the time I publish this Nougat package, which is sort of in an alpha state, I'm not publishing it and there's tons of people consuming it and going to break them. But I'm the primary consumer of this. And I got things to a point where I thought I was, you know, happy with it. And when I finally went to go consume it inside of Brand Ghost, which is a social media and cross-osting scheduling application that I have, it didn't work. Now, it didn't work in some aspects, it worked in others, but there's a couple of sort of breaking changes that we need to go address. So, long story short on this, I just wanted to show you that I, you know, published my my alpha, you know, 2 version of this. And when I go to consume it, we jump over to the code. I have a couple of files that I bookmarked here just because they don't work and they used to. So, I broke APIs and it's not like a matter of, oh, let me just go use the new API that we have. In fact, it just doesn't work and it won't work. So, I need to come up with a better solution. The first three files that I have bookmarked up at the top here are really sort of the same problem. And I'll give you a little bit of context if you don't know the codebase. And spoiler alert, you probably don't. Uh, you won't really understand these, and that's totally cool. But I have something called a plug-in factory. And the way that we used to do this is that whenever you needed, the plug-in factory, there's no state for it. It's just a helper class. And so you could new one up on the spot and then you could ask the plug-in factory to go build plugins for you. And so I have that here where I needed that passed into this class. I had it in here um down here. There we go. So, I needed to be able to get a plug-in factory and I used to just new it up on the spot. And there's one more spot over here. Same thing. Used to be able to new up a plug-in factory on the spot. And we can't do that anymore. And the reason for that is that in Needler, I went from having reflection as sort of the implicit default way to do things because that was the only way that it worked to now we have source generation as an option. And I went as far as to say that I don't want either of those things to be implicit. I want to make sure that the developer is selecting if they want source generation or they want reflection. And that means that on the consuming side in my codebase these files that we're looking at where this code is running is not at a point where it has enough decisionmaking power to say ah yes use the new source generation one or ah yes stick to reflection. It's at a point where it's like hey man I don't know what plug-in factory I need to work with just just give me one. We can't resolve it off the dependency container though because this code runs before that. Okay. So again, if you're not familiar with dependency injection and what I'm getting at here is that usually in a situation like this, if you needed an I plugin factory, you would simply use dependency injection to pass it in. This is before dependency injection gets to kick in. So we don't have that luxury. And that's the same thing in all these spots. We're we're setting up the dependency injection uh in all of these three spots. We used to be able to make this thing. Now the code at least in these three spots does not have enough context. Okay. So we need to basically ask someone else for it and we should be able to have co-pilot figure out who that someone is. So what I'm going to do is I'm going to take these three code examples. I'm going to give them to co-pilot on the CLI and we're going to kind of go into a planning mode with it and see what it has to say. Before I do that, just want to jump over to one more spot. This is one more breaking um sort of compilation issue because we're missing some types and things now. So, this one is a little bit different and I will need C-pilot to solve this in a different way. And when I did all of my code changes with Claude and C-Pilot on the Nougat package side, we didn't come up with the migration plan. And that's okay. I'm really the only person that I have to worry about migrating for this. I don't care. But now that I'm looking at this, I'm going I actually don't know what the new classes are supposed to be or the new patterns are supposed to be. And I would like to have co-pilot look at the code and say like based on what we have now, here's the new suggested pattern. So these are both examples of things I can go figure out. I just thought it would be cool to use AI to do it. We're going to start with this part. So I'm going to go over to the Copilot CLI which I have pulled up here just to show you. I have I go to model. I am using Opus 4.5 at the time of recording. So I have that there. So, I'm going to say that we have some breaking changes in the needler nougat package. This was intended that it's not backwards compatible, but there are some other opportunities. So, I'm giving it a little bit of context. Unfortunately, I was so excited. I did all this work over the weekend to go make all this happen and then I restarted my computer and lost the entire console context and I was really pumped to go make videos and show you the different parts of what was going on. So I'm just giving it this uh sort of information about what we did. Right. So basically we did this migration of some sort. There's breaking changes that's planned but there's about to be some other things that we didn't really expect. I have several code examples that no longer work on the um host application consuming on I should say on a different host application consuming the Nougat package and we have issues with not being able to access a plug I should say it an I plugin factory instance. I'm going to paste in the code and then I'm going to give it some instructions after basically to say I would like you to come up with a design and several options for how we can make this happen. So remember first three files here. So I'm going to give it this. What's interesting is like a lot of the contents in here it don't it it won't care about it doesn't matter but it knows what type of plugins these are. These are from Needler itself. So there's one I'm going to give it the next one. There's probably let's see I might see if I can clean this one up a little bit. It's just going to be a lot of extra stuff that doesn't matter. What's a good way to do that? Okay. I just want to clean up some of the code cuz it's like I say clean it up. uh literally just deleting stuff, but it's so that it's less noisy. Sure. And I'll I'll keep that in. Again, these details don't matter necessarily. I'm just trying to walk you through how I am approaching this so that you have some context and understand like, you know, there's no magic when we're doing stuff like this if you're having some challenges. And we'll do one more cuz I think there's a lot of stuff that's floating around online where you have lots of people saying like, "Oh, I did this with AI and it was so simple and like it wrote a million lines of code and like I'm Mark Zuckerberg and then you have other people that are like AI can't do anything." Um, the truth is somewhere between those and so I just like showing you kind of what I'm doing and how things are working for me. So three examples are pasted in and now I want to say I would like you to design a solution for providing these locations in code which are needler specific plugins with an I plugin factory instance provide several options usually Usually, uh, I would be a little bit more specific about how many options, what I'm looking for in the options, but like, let's just see what happens because I think it should do an okay job because I I don't think that to be able to plum this through is going to be that difficult. I'm just curious to see what it does. It's starting. These are three tasks running in parallel. If it's not totally obvious to you, these explore tasks are truly going in parallel here. So if you're watching closely, like the console's updating, not like it's printing new lines, but the the different areas are updating on the spot. So now it has a clear picture. So it's done some exploration. Let me look at the exact uh record definitions. As that's going, I'm just going to explain a little bit. there are um these DTOs or these positional records that feed in to those plug-in methods and that way we can add more information onto them without changing the whole signature cuz if there's 100 plugins and I need to go add one more parameter then I need to go update that in a 100 spots and because I am the one publishing this Nougat package I don't want to go break everyone it means that where I'm creating these options those are the spots that breaking changes. So it it should minimize it but we already have three options right it's done. Okay, so its recommendation is option one, direct edition. And then given that you've already stayed breaking changes are intended, the plug-in factory is already in the scope of at the all creation sites. Kind of what I was hoping to see. It's the cleanest, most explicit API. Okay, let's see what options it had. And again, I want to show you this because this is how I went from taking needler, which is all reflectionbased, over to source generated. When I sat down with both claude code and co-pilot, cloud code has a plan mode, I'm just effectively doing the same thing here, similar enough thing here where I'm asking it for options. Option one is to add in this plug-in factory rate on all these options. So if I go down here, it means that I would literally have access to it just like this. And so all these examples would just work right away. And based on its analysis, wherever we're creating these options, it's saying we already have the plug-in factory there. So we can just pass it along. So that's cool. Works across all three. Cons, it says breaking change for existing plugins. Constructor signature change. Yeah, but that's on the options. It's not on the plug-in itself. So that's fine. increases the record size. I don't care. That's the whole point of me having that record register I plug in factory and DI container. This would be ideal. I don't think it will work because of the time where it's happening. Register I plugin factory on the service collection. Like I said, this is what I would expect. I kind of hinted as we walked through the source code. This is how I would want to do it. But the problem is like these things are running before that happens. So, and it it notices that, right? So, it actually figured that out. I web application builder plugin runs before services are built. It won't work. I service collection plugin also runs during service registration phase. Won't work. It only works for postbu plugins. Okay. So I have I didn't tell you all this but I have these different flavors of plugins that are built into Needler and C-Pilot you saw what I typed right? Copilot was able to figure out like nope not going to work in these cases. Option three is a hybrid add optional property with default. I don't like that because then yeah people who are asking for it have to check. Doesn't feel good cuz then people have to check right it says nullable property requires null checks. I don't want everyone have to do that. Runtime failure versus compile time safety. Option three is not an option. Interfacebased context accessor. That sounds like a mouthful. What does that mean? I plug in factory aare and then authentication plugin. Oh, interesting. So these things implement this and then we can assign. No, I don't like um set only like externally set only properties. I hate that. So no, I think Oh, there's option five. Oh my god. Okay. [laughter] Keep records unchanged. Add extension methods that extract from services. So, we can't do this because this is the same problem in terms of the order of operations that in these locations where we want this, we don't have the service provider. I'm not going to go build a service provider to go resolve this thing. Would be crazy overhead. So, we're not going to do that. If we didn't have to build, just as an example, if we didn't need this line, it even says it's a temporary provider. If we didn't need that, I would be okay with this extension method. If we just said hey there is a service provider like the service list here get the required one I'm okay with an extension method like that option one's the best choice so um implement option one ensure tests are updated to validate that this works for both reflection and source generation I'm saying as necessary because the spots in the code where it's going to do this it might be agnostic to those code paths like a decision around reflection or source generation. I don't know. Why don't I know? Because I just had co-pilot and cloud build this all for me over the weekend and I really have to go learn my own code. But I wanted to put this video together. So, we'll send that off. At this point, I'm going to let this finish and what I will do is I will ask my awesome editor to go splice some videos together when this is done. And I will have it go do the other one as well. And then you can see the output of that when it's all polished up. So see you in just a moment. All right. And we have a successful output from C-pilot mostly. So it was able to get the first part pretty easily. And I'm just going to pull up git extensions to show you. And I already made the commit here. So let me go ahead and expand this. And I'm going to click through this pretty fast because details don't really matter to you. But the point is that it was right. So, it was able to go add in this plug-in factory on all these options, right? So, where's the other one? Here's another options, right? Here's another options. So, it could pass in the plug-in factory. And it said that we have access to this plug-in factory in every spot where we're making these options. So, if I click through some of the other spots, you can see that it's just passing in that plug-in factory, right? So, that's the only change in here that was done. This one, they just changed the order, right? So that we could get the plug-in factory before we call this code. Now we want to pass it in here, right? We have a plug-in factory. We have a plug-in factory. We have a plug-in factory. Like it was just available in all the spots. So that made it super easy again in this spot. And then I noticed it touched some tests because I had asked it to, right? I said make sure that we have some coverage on this. It even added new tests. These ones are probably not super helpful to be honest. I'm just kind of reading through this. plug-in options, plug-in factory tests. This set of tests is probably overkill in my opinion. The reality is, and you won't know this unless you know the codebase, there's a lot of other tests already that are doing it. And I think that if we added a couple of assertions in existing tests, we probably could have got the confidence we need. But like you can see, well, maybe it's not obvious. The other video I made, I was talking about how I put in some parody tests because we have reflection and we have source generation. And so it added in parity tests into here, right? This whole file is parody tests. I don't know like I wasn't very clear with it. I kind of gave it some freedom. So it did what it said. I think that's probably fine. In a couple of these other spots, it had to go update tests to pass in the plug-in factory. When I see like a block of code changing like that, that makes me a little nervous. But I think that it actually just refactored some of this out and pulled it out up here. Same thing. This code is really coming from here. So, it's at least explainable. I don't love when it touches maybe more than it needs to, but I think that's the right thing. Also, adding it in here. There's a couple more test files where we're just adding in the plug-in factory where it needs to be called or else it won't compile. But, you know, co-pilot told me, hey, look, it all passes. This one is the other set of tests. My apologies. This is the part. So, you know, seven tests validating the plug-in factory access. The the reality is like it said it worked and I still don't trust it. I almost never trust LLMs at this point. When they tell me things work, I I need to go validate. and I ran the test in Visual Studio and they did pass. So, next up was the other option here. By the way, I'm not publishing that Nougat package to show you it being consumed. I want to get this part sorted out first and then I'll publish it. So, this is uh or I said great, that worked just to give it a break in terms of the context. Right? One more issue we need to fix. This is the second one that I introduced is that uh some of the consumer setup needs an equivalent migration path. assume they're just sticking with the legacy reflection usage because I don't want it to be confused about, oh, they're trying to migrate to source generation. Not the goal here. That'll happen. Sticking to reflection just for now. But they want to upgrade to the latest Nougat package. And then I gave it the code. And I thought I was being smart. And then I remembered when it gave me this response that it can't see the failures. I'm in a completely different working space. So it's like okay here's what it's using. They're missing the using reflection part and they're like that's a simple migration and they're right that is missing and that is simple but then it said like or did I miss my text basically I told it like that's not it right it it said you're just missing this. That's not all that's missing but it doesn't know. So it said is this the only issue they're facing or are there additional API changes that need migration support? So I told it explicitly like these lines it just doesn't work and then I said that this doesn't exist either. This is just a good example of like me being stupid and not reading my own code that AI changed. I thought that we migrated away from having this class at all. I am lazy apparently because if I would have just searched in the code, it is available still. I was missing one of my Nougat package references. So, it's a very easy one to fix because I don't have to change any code. It will work. This one is a little different and it was able to come up with a suggestion for it. Ease reflection and then this part here. I mean, it actually gave the output right here. It's just reflection type filter instead of default. So, it this thing got renamed. [laughter] I'm missing this line because now we need to have explicit request for reflection. And then I was missing this Nougat package that is specifically for reflection. So literally this is just I mean couple things here. One, I'm being dumb and I should have caught that. Didn't see it. I feel kind of silly. That's okay. Copilot figured it out, right? Not much effort on Copilot's part. This is again just another sort of reason or angle for you to look at that if you're stuck on stuff and you don't know. You can talk to an LLM and have it debug and sort through things for you. I wouldn't, you know, give up all of your debugging skills. I think it's a good thing to have and clearly mine are eroding uh very quickly. So, it got that part handled. I think this also speaks to the fact that the migration work that Claude and Copilot did to get us here actually worked quite well. In fact, just by looking at these key changes that are required, it's almost nothing. I renamed something. This was a a conscious decision for a breaking change and it's one line to add. And then this is just me being stupid and not adding in a Nougat package. So overall, a super easy fix on this part. At this point, I feel like I can publish the new Nougat package because the second issue is literally no code changes required on the Nougat side on the sort of uh the package that I'm publishing. We already committed that one. I just got to push it up for the first issue and I should be able to consume it. So hopefully you thought that was kind of interesting in some different ways that you can play around with uh Copilot CLI. I'm trying to take more time to use different tools, try them out and work in them. So, you could have done this with Claude, you could have done this with GitHub Copilot in Visual Studio, I'm sure. I'm just showing you a different example of using the Copilot CLI so you can see it in action and see how I'm working through things. So, thank you so much for watching and I will see you in the next video. Take care.

Frequently Asked Questions

What is the main purpose of using Copilot CLI in this video?

In this video, I'm using Copilot CLI to help fix issues in my Nougat package, specifically addressing breaking changes and improving the integration of my code. I want to see how well it can assist in resolving the problems I've encountered after migrating from reflection to source generation.

Why did you decide to switch from reflection to source generation in your Nougat package?

I decided to switch from reflection to source generation because I wanted to provide developers with a choice between the two methods. This change allows for better performance and more explicit control over how plugins are created, rather than relying on implicit defaults.

What challenges did you face when integrating the new Nougat package into your application?

When I tried to integrate the new Nougat package into my application, I encountered several breaking changes that caused some parts of the code to fail. Specifically, I had issues with accessing the plugin factory instance due to changes in how dependencies are managed, which required me to come up with new solutions to resolve those issues.

These FAQs were generated by AI from the video transcript.
An error has occurred. This application may no longer respond until reloaded. Reload