leonardochaia/dotnet-affected

split code to library and CLI

shlomiassaf opened this issue · 10 comments

Thank you for this tool!

I would like to suggest splitting it into a standalone library and cli tool.

We have a dedicated process with an internal tool and integration this one would be great however it only comes as a CLI tool.

It will be great to have this as a library and getting back the list of projects as the response and doing whatever we need with it.

Hi @shlomiassaf , I agree with you. Code is kinda split into the main assembly already, so porting to a package should not be a big deal.

A new "core" package would be packed including the affected detection algorithm (domain, infrastructure). The execution layer (the affected cli) would be shipped separately in the current package and would depend on the core pacakge.

The main entrypoint would be the IAffectedExecutor which would output what you need in the AffectedSummary.

Would that work for your use case?

Yes.

I did it locally, it requires additional changes since domain and infrastructure has some "leaks".

  1. The core library should not used DI so this must be handled.
  2. Some classes has IConsole injections, logging must be in the CLI tool not the core lib
  3. ProjectInfo should move to the domain dir
  4. CommandExecutionData needs to change (I did AffectedOptions and removed the ctor params, added setter the props)
    In addition it must loose the properties: verbose, format, dryRun, outputDir, outputName as they are CLI specific.
  5. ICommandExecutionContext & CommandExecutionContext changed to IAffectedResults & AffectedResults
    Also added property to both (public AffectedSummary AffectedSummary => _summary.Value;)

To make it user friendly I also added this helper:

public static class Affected
{
    public static async Task<IAffectedResults> DetectChanges(AffectedOptions affectedOptions)
    {
        var projectGraphRef = new ProjectGraphRef(affectedOptions);
        var changesProviderRef = new ChangesProviderRef(new GitChangesProvider(),
                                                        new AssumptionChangesProvider(projectGraphRef, affectedOptions),
                                                        affectedOptions);
        var changedProjectsProvider = new ChangedProjectsProvider(projectGraphRef, affectedOptions);

        var executor = new AffectedExecutor(affectedOptions, changesProviderRef, projectGraphRef, changedProjectsProvider);
        var results = new AffectedResults(executor);
        await Task.Run(async () =>
        {
            return results.ChangedProjects;
        });

        return results;
    }
}

And ofcourse, adding the CLI functionality removed (output, verbose, dryRun, etc) in the CLI lib

Once this is done, you can easily create an additional lib (or within the core) with special build "Task" files that will allow
running the build/test etc only on affected files without using the CLI

E.G

dotnet test /t:Affected

My dude, this is amazing.

One of the goals is to have an MSBuild Task #17

domain and infrastructure has some "leaks".

Yeah, I would expect that since for simplicity I just threw everything in the same assembly.
I know a refactor is due. It will also simplify testing. I like where this is heading and the changes you suggest.

I may find some time to work on the refactor during the weekened. Once that's done we will track the MSBuild task in #17

Hi @shlomiassaf, with the changes from #52, we can do this:

var graph = new ProjectGraph(...)
var executor = new AffectedExecutor(new AffectedOptions(Repository.Path), graph);

var summary = executor.Execute();

I think this would allow us to create a task that gets the summary and calls the msbuild task to build those projects?

@shlomiassaf do you have experience with msbuild tasks / targets?
If you can point me in the right direction I may give it a go but I'm not sure how to build it.

I'm thinking something that can hook into "the projects ms build is gonna build" and narrow that list down?

There are online projects.

https://github.com/dotnet/aspnetcore/tree/main/eng/tools/RepoTasks
This is the "in-repo" tasks that run live C# code for the task itself.
It has C# Task code that add's xml instructions to the build, alter it, etc so you can filter what to build

You can also look at the "small" SDKs which actually are example of how to work with tasks to create a build feature/s:

The pervious way to do central package versions, no code, just build schema manipulation:
https://github.com/microsoft/MSBuildSdks/tree/main/src/CentralPackageVersions/Sdk

The actual traversal SDK, same here, no code just build schema manipulation.
https://github.com/microsoft/MSBuildSdks/blob/main/src/Traversal/Sdk
This is also a great example of how to use batching

If you'll face issues, i'll try to find time to help.

I think first you need to have the libraries published and working, as a starting point.

Hey. Appreciate the tips! Will take a look.

I think first you need to have the libraries published and working, as a starting point.

Yeahp, will do soon, perhaps today. I think #52 can be merged as is. The remaining changes (mostly to improve the CLI) will be done in another PRs.

Hi.

DotnetAffected.Core has been released 👍