Replacing a batch deployment script with a .NET deployment app

One of the projects that I'm working on has this batch script that is used to build and deploy the app. That process started fairly simple that a batch file was all that we needed, but I think the project has outgrown it now and I thought I want to write a small C# app that'll do the same.

The existing batch script looks something like this:

tool_1 run with this --flag
if !success, goto fail

tool_2 run
if !success, try tool_2 again
if !success goto fail

tool_3 run
if !success goto fail

tool_4 run
if !success goto fail

if something do copy some files here and there
if !success, goto fail

do some special stuff here and there
...

So the pattern I could see here was a bunch of general commands like exec tool_1 <args>, that's (1), the pattern of if !success, goto fail obviously, moving files, and miscellaneous stuff.

So based on that I thought I wanted the programming model to look like this:
(I was trying to create something that I can reuse in other projects moving forward)

MagicDeployHelper
    .StartStopOnError()
    .Call("tool_1", "run with this --flag")
    .Call("tool_2", "run", tries: 2)
    .Call("tool_3", "run")
    .Call("tool_4", "run")

But actually tool_3 and tool_4 can run at the same time. It would have been a paint (I don't even know if it's posssible) to do that in batch, but since I have more freedom here let's put something in for that.

MagicDeployHelper
    .StartStopOnError()
    .Call("tool_1", "run with this --flag")
    .Call("tool_2", "run", tries: 2)
    .ParallelCall(p => p
        .Call("tool_3", "run")
        .Call("tool_4", "run"))
    .RunCustomLogic()
    .Copy("from here", "to there")
    .RunAnotherCustomLogic()
    .Run();

RunCustomLogic() and RunAnotherCustomLogic() calls are pretty important. I wanted to easily extend the base functionality and maintain the order of execution.

(1) the Call() method makes it very easy to call tools in order. (2) ParallelCall() also allows me to run 2 things at the same time which I wasn't able to do before. (3) Built-in Copy() function since that happens a lot. (4) if !success, goto fail encapsulated easily in the type of the deployment object. But can also be overridden on individual calls like:

    .Call("tool_x", "arg", stopOnError: false)

Finally there is the ability to plugin custom steps in order like that.

for the programming model of RunCustomLogic() I went with something like this:

public static IDeployment RunCustomLogic(this IDeployment deployment)
{
    return deployment.AddStep(() =>
    {
        if (DateTime.Now < DateTime.Tomorrow)
        {
            File.WriteAllText("C:\bios", "It makes sense");
        }
    });
}

which probably can be added directly inline above, but I like to break things down in extension methods. All the code for this is here https://github.com/ahmelsayed/DeploymentSdk