Add `nuke --what-if` to see what commands would be executed without actually running them
Description
Add an optional switch to nuke, allowing it to run the build and only outputing commands expected to run in the console, not actually running them. This could be useful for development/test purposes.
Usage Example
> nuke --what-if --no-logo
NUKE Execution Engine version 8.0.0 (Windows,.NETCoreApp,Version=v8.0)
╬════════════
║ Compile
╬═══
15:27:02 [INF] > "C:\Program Files\Docker\docker.exe" build --tag ghcr.io/mydockerimage:0.0.32-ci-nuke D:\sources\repos\mygithubrepo\src
15:27:02 [DBG] Running command in whatif mode, not actually executing
╬════════════
║ Publish
╬═══
15:27:03 [INF] > "C:\Program Files\Docker\docker.exe" push ghcr.io/mydockerimage:0.0.32-ci-nuke
15:27:03 [DBG] Running command in whatif mode, not actually executing
Alternative
Duplicate commands in a Console.WriteLine(), meaning there could be copy/paste errors.
Could you help with a pull-request?
No
Why not just using nuke --plan which generates an HTML page where you can see what is executed when hovering over the "Target-rectangles"?
nuke --plan displays the targets, but it does not include the actual command(s) that is/are executed. In my exemple, I'm interested in knowing that the target Compile actually runs "C:\Program Files\Docker\docker.exe" build --tag ghcr.io/mydockerimage:0.0.32-ci-nuke D:\sources\repos\mygithubrepo\src
This feature would never work reliably. You'd have to classify all APIs as read or write operations, and encapsulate them with an aspect.
This feature would never work reliably. You'd have to classify all APIs as
readorwriteoperations, and encapsulate them with an aspect.
Huh ? why that ?
The idea is simply to Console.Write the commands instead of executing them. There is no need to discriminate between read or write operations.
What exactly would you do if a target has File.Delete in it?
Since it's a framework method and not a Nuke task, delete a file.
Such calls could be protected with some sort of if(WhatIf) { }.
Then you can do the same for CLI invocations.
Bottom line, like I said, the feature would not work reliably. You would not be able to walk to a build project, and be confident to ask "what if".
The main difference is that File.Delete executes some operations from within the process context.
Framework methods don't have such thing as a "command line".
In other words, running rm $filename is not exactly the same as File.Delete($filename).
But when you call something like DockerTasks.DockerBuild( ... ) it creates a new process, hence the executable + CLI parameters being known as a requirement to invoke the command. The problem is that it is tricky to know what actual command will be executed at runtime, given parameters, since how the task turns into an actual CLI command is an implementation detail of the Task class, which is hidden to the build developer.
I understand you don't want to develop this feature and that's really sad.
It isn't hidden for the most part: ToolSettings.GetProcessArguments()
I understand you don't want to develop this feature
Not fully true. I would have liked something like this, but consistency and reliability are strong arguments against it.
ToolSettings.GetProcessArguments()
Is there any documentation on this topic ?
I might think about adding a settable delegate in the new task implementation: https://github.com/nuke-build/nuke/blob/44173c559ea1e140840cb31bbbc91fb6c69d967e/source/Nuke.Tooling/New/ToolTasks.Run.cs#L16
But right underneath you can already see the next culprit. Attributes like [GitVersion] et al wouldn't be able to resolve values from the CLI call, because no command is executed. Parsing will fail, so will targets that "require" these values to be present.