I’ve written quite a few blogs here on how you can use .NET Core in your applications and what to expect when developing for this new platform. But with .NET Core being open source there’s also another story to be told, namely that of extending and improving the platform itself through open source contributions. So when Karel Zikmund from the .NET Core team reached out on Twitter asking the community to help them fix bugs before the .NET Core 2.0 release I knew that it would be a great opportunity to get my feed wet contributing to .NET Core. In fact, together with one of my colleagues at Info Support we thought it would be a great idea to organise a hackathon so we can get together, have a bit of fun and fix some .NET Core bugs in the process. So we decided to do just that and have already set the date (29th) and location (Startup Village). Of course we wanted to get a feel for the process of actually doing a contribution to .NET Core before we get together so that we don’t run into any surprises. I’ve done a few contributions to other projects in the past, but nothing quite as big as .NET Core. So last week I did my first contribution and I thought it would be a good idea to write about my experience.
Finding an issue to work on
Before we can do anything we’ll need something to work on, so we’ll need to find an issue in one (of the many) repos on GitHub. Since the post on Twitter by Karel got me to the corefx repo, where the base class library is being maintained, this seemed like a natural place to start. By filtering and sorting the issues on GitHub I was able to find a relatively easy issue to start with. Notice though that the list of issues to work on for the 2.0.0 milestone is already getting a bit thin. Once I found an issue I had a look through the code to see if I could understand the issue. In this case it seemed like a fairly straightforward issue that could be easily reproduced with a unit test. But before I could write one I needed to get the code and build it.
Getting and building the code
Getting the code is a fairly straightforward process. First you create a fork up on GitHub so that you have your own repository to work with. This is necessary since you won’t have the rights to write to the corefx repository directly. Instead we’ll need to use pull requests to get our changes in (more on that in a bit). After we’ve created the fork we can clone the fork onto our local machine using git clone. Next step is building the code so that we can work with it. Luckily there is a great developers guide up on GitHub that has many of the details you’ll need to build the code. Also make sure you have the necessary pre-requisites for your chosen platform which you can find by following the Instructions link at the top of the developers guide. I decided to do this on my Mac, rather than on Windows, mainly because of the list of pre-requisites. On Windows you will need the Visual Studio C++ tools and libraries, which eat up quite a bit of disk space, while on macOS the list of pre-requisites is considerably smaller. Unfortunately that also meant that I didn’t get much IDE support. You can open the files with Visual Studio Code, but you won’t get IntelliSense. This is because the project files in the corefx repo are still using the old MSBuild format, which Visual Studio Code doesn’t understand. Hopefully this will change in the future. Once I had all of the pre-requisites installed I ran the build script to run the build. This was a very smooth experience in my opinion. I’ve had countless of projects that you check out from source control and try to build which just fail instantly, but not in this case. After the build script ran succesfully I had to run build-tests as well which builds and runs the tests for the entire repo. Obviously this takes some time since there’s quite a lot of code in there, but I think all in all it doesn’t take much longer than half an hour on my machine to build everything and run the tests which is pretty decent. I did have some failing tests, but I decided to ignore them for now since they pertained to a part of the code that I wasn’t going to touch just yet.
Making some changes
Now that I had successfully build and ran the existing tests it was time to write a new test that showed me that there was indeed a bug as described in the issue. This was pretty easy to do. I just copied an existing test and modified it a bit for this particular scenario. After I wrote it however I wanted to run the tests for just the part of the code I was going to change (in this case the System.Security.Cryptography.X509Certificates assembly). According to the developer guide I should be able to go into the tests folder and run msbuild /t:BuildAndTest from there. Unfortunately it didn’t work for me and I got presented with a vague MSBuild error that complained about something called OverrideToolPath. Googling for the error did give me some pointers and I even found an open issue on the corefx repo, so I figured it was just a problem of the corefx repo using stuff from the tooling that wasn’t released just yet. So I worked around it by just building everything again and then running the tests again. After a while of doing this it became a pretty frustrating experience, since writing correct code without IntelliSense isn’t the easiest thing in the world. Fortunately it turned out it was just a case of me not having read the guide properly, since it does point out that on Linux and macOS we have to run the msbuild.sh script from the tools folder in the root of the repo instead of running msbuild directly. This makes sense since the corefx repo uses a private build of the tooling, and doesn’t work properly with the released version that is installed on my machine. So with that resolved my productivity increased a bit and I had a test that compiled and it failed because the incorrect type of exception was being thrown (a NullReferenceException instead of an ArgumentNullException that was desired according to the issue). All I had to do now is fix the bug, easy right? Well, again, I should have read the guide more carefully, because after I made a change to the code that I thought would fix the bug, my test was still failing. Of course, running msbuild /t:BuildAndTest only compiles the test code and runs it, but it doesn’t re-compile the actual implementation so my test was still testing the old code, instead of the new. After realising this I opened two terminals inside Visual Studio Code (which is an awesome feature, by the way) and had one in the src folder and the other in the tests folder so I could quickly build and run the tests by just switching between those terminals. And sure enough, after recompiling the assembly and running the tests again my test was passing and the bug was fixed. So the time had come to open a pull request.
Doing a pull request
Before I even started the work on the fix I created a new branch in my own repository to do the fix in. So creating a pull request was just a matter of going to GitHub and clicking the link to create the pull request. Be sure to have a look at the contribution guide which has some do’s and don’ts when it comes to commit messages and pull requests. Also, you’ll want to make sure that you’ve signed the contributor license agreement, which is a requirement for contributing code to .NET Core. I opened the pull request on Tuesday evening (local time) before I went to bed. When I woke up the next morning I had already received a review from one of the team members. Awesome! Someone from the team also thanked me for the contribution towards a 2.0.0 bug, which was nice to see. The review comments I received were very detailed and specific. This is great, since it was easy for me to pick it up. During the pull request we even changed the exception type again from a ArgumentNullException to a CryptographicException so that ultimately the code would be compatible with what the .NET Framework used to do. They even looked at the order in which exceptions were thrown, so I had to move the if check that I added down a bit so that the behaviour would be consistent with .NET Framework. I also had some unnecessary code in the test I added (since I copied it from an existing one), so I removed that as well. All in all I was impressed with how thoroughly the code was reviewed (all the way down to unnecessary white space that my editor added). I fixed the comments when I had some free time during the day and I by the end of Wednesday my pull request was merged and Karel invited me to become a collaborator so they could assign more issues to me so I can work on them. I already have one assigned which is around the same area, but this time I will have to add some new APIs as well which Im sure is going to be quite another experience.
Conclusion
All in all it was a great experience to make a contribution to .NET Core. I know this is just a really small thing, but that also what made it an ideal issue to get started with. It already feels great knowing that a small piece of code I wrote is going to end up in a product that is going to be used by many people. I was impressed with how easy it was to get started writing code. Building the code and running the tests doesnt take ages, and once you’ve ran an initial build on the entire repo you’ll only have to build and run the tests for the bits that you’re touching (although when pulling in large sets of changes from the main repo you’ll probably want to run the entire build again). The way my code was reviewed with constructive feedback, and the thank you comments made by team members also kept me motivated. I’m already looking forward to working on my next issue. Finally I would encourage anyone with some programming skills and an interest in .NET Core to have a look and see what you can contribute. In the end, we can all make it a better platform than it is today. Just be sure to read the contribution guide first to avoid nasty surprises.