Introducing Elephant Projects - Cross-repository refactoring
At my place of work, we maintain a product which has 413 projects (.csproj files) spread over 15 different repositories. Some repositories are big (our SDK), and others are smaller (utilities for single purposes). One of the issues I face with this scale, is that at times we want to make a new feature or bugfix within the SDK or some other low level assembly, without really knowing what the end result looks like (we're a small team). In a classical manner, we would be coding in the SDK, publishing packages locally, restore those packages in our application and then using the new code - if a bug appears or a method isn't quite right, it's back to step 1.
I've envised a method to link these repositories together, to work locally as if they were one big repository with all projects in it. In short, this works by replacing our PackageReference's with ProjectReference's.
Meet ElephantProject (get it on NuGet).
With ElephantProject, I can quickly rewrite all projects to reference projects instead of NuGet packages, and then also create a solution file with just the right set of projects in it.
Note: We never commit these project changes to source control. This is purely for local development and debugging.
Use case - refactoring
In my local work directory, I will typically have all repositories checked out (and kept up to date with mu), I'll call this directory "Work". With ElephantProject, I can now run:
elephant-project rewrite -d Work
(I don't actually have to specify the directory, it defaults to the Working Directory)
This alters all
csproj files it finds replacing all package references with project references. ElephantProject intelligently resolves the csproj's to find their
AssemblyName, in order to determine which package each project represents in order to do the matchmaking.
The command will output how many references it's modified for each project.
Once that's done, I can then run the
elephant-project sln -d Work MySolution.sln -i MyApplication/**
This command intelligently finds all projects within
MyApplication, and adds these to the solution file
MySolution.sln. It then finds all the project-based dependencies for the
MyApplication projects, and adds those as well. After the rewrite, this will include all the SDK projects we had in my local Work folder.
MySolution.sln will now give me a workable product, that is compiled fom scratch, from the SDK all the way to the application.
I will typically maintain many solutions, such as:
elephant-project sln -d Work Full.sln
elephant-project sln -d Work Application.sln -i MyApplication/**
elephant-project sln -d Work ApplicationAndSDK.sln -i MyApplication/** -i MySDK/**
Whenever new projects are added, or dependencies change, I can run those commands again to update all my solution files.
Use case: Keeping many solution files up to date
In some of our repositories, we have many small applications each perfoming some subtask. Usually, developers want to work on just one of those applications - other times they want to open up the entire repository at once. For these use cases, I maintain a small solution file for each application, in addition to the "normal" solution file in the repository root.
These solutionfiles come out of date quickly - if a developer adds a dependency or an application, but forget to maintain all affected solution files, others will find themselves in a pinch.
Not to fret! ElephantProject can fix this for us.
For work, I've created a script that iterates all the combinations of solution files we want to have (one per app, one for the repo, one without tests, ..), which brings them all up to date. Because the sln command automatically finds all dependencies, we just need to tell it which projects we're interested in, and it will add the rest.
# Create one for the root elephant-project sln Root.sln -i Applications/** # Create one for each application # This is pseudo-code, adapt as needed apps = $(ls Applications) for $i in $apps elephant-project sln Applications\$i\$i.sln -i Applications/$i/**
Once this has run, all solution files will be up to date.