Obsolete comment; DescribableHelperTest is pretty thorough.
Switching test to use preferred object binding idiom.
Running some tests in Groovy sandbox to prove they pass.
Added BodyInvoker to create room for more control over how to invoke body.

Such control includes how FlowNodes are created, the display name for the body invocation, additional Actions, etc.
Promoted the Outcome class over to the API

... as a preparation of providing StepContext after the body execution
Introducing BodyExecutionCallback

Introducing BodyExecutionCallback as a beefed up version of
FutureCallback, so that the step implementation can interact with the
start body block / end body block, such as adding log messages.

We do this by creating a different StepContext objects that are only
valid during the body start and body end.  This in turn allow Steps to
re-inject the context to access correct TaskListeners and things like
that (which is not in this commit.)

Copying my email to jenkinsci-dev for the motivation:
------
I'm working on this card, where we want to be able to write to console
log and do stuff at the end of the body invocation.

The challenge here is that the Step API has no dependency to the
workflow Flow Node API (it goes the other way around), so we need to do
this in a way that doesn't force Flow API into the likes of RetryStep.
That pretty much means we need to do the context injection of
TaskListener like StepContext does.

I thought about two ways to do this.

One is to reuse the existing StepContext instance. We could just say
that at the point of the callback from the body execution,
StepContet.get() would return the context objects for the end of the
body (TaskListener connecte to the right FlowNode, etc.) We could then
provide some convenience base class that performs @StepContextParameter
injection, so that everything gets reinjected.

This works, but I also feel that it's bit brittle, especially for
ParallelStep that invokes multiple bodies at the same time, and thus it
wants multiple different post body execution context. So I started
thinking about another way, where the end of the body execution is
notified to FutureCallback<BodyExecutionResult> instead of
FutureCallback<Object>, and the newly added BodyExecutionResult class
would have properties like outcome, the same get(Class) method that
returns contextual object, and so on.

That also makes it more explicit that the context injection works
differently post body execution.
Introducing BodyExecutionCallback #2

CPS engine side of the change to fire newly added callbacks of
BodyExecutionCallback
Shuffling code between CpsBodyInvoker and CpsBodyExecution.

... to make their lifecycles clearer. Namely, CpsBodyInvoker is a builder pattern to accumulate
possibly non-serializable parameters, then once it gets going CpsBodyExecution represents
the running program state.

The time between CpsBodyInvoker.start() and CpsBodyInvoker.launch() is where two objects reside side by side.
BodyExecutionCallback provides the opportunity to interact with FlowNode, including adding Actions.

So I removed WorkflowBodyInvoker whose sole purpose was to add Actions to the start node.
Honor skip body block.
Where we don't invoke body multiple times, there's no point in creating a nested body block nodes.

This simplifies the flow graph, hence the visualization
These fields shouldn't be persisted
To preserve the order of invocation it needs to be List.