STASH LOCAL
Runs the ops underneath it against a private copy of the stash, then throws the
copy away. Values written inside the block are meant to stay inside it, so a sub-section of a rule
can use short names like path or count without stepping on the same names elsewhere.
That is the design. In practice the rule designer will not let you put anything inside it, which decides whether the op is any use to you.
Fields¶
There is no form. The Config tab carries the standard Name box, which relabels the op in the rule
tree, and a YAML editor that opens empty. The op reads nothing out of that editor, so keys you type
there are saved with the rule and then ignored. The Options tab is the full one, including
Run Rollback, Enabled and Error Handling.
It will not take children in the designer¶
In the rule designer this op behaves as a leaf. Drag an op onto it and the op lands after it as a sibling rather than inside it. The keyboard nesting shortcut refuses it, pasting into it refuses it, and importing a subtree into it reports that you cannot import into a leaf node.
A STASH LOCAL you build today therefore has nothing inside it, scopes nothing, and does nothing at all when the rule runs. It is not an error and it will not show up in any log. The ops you meant to put inside it run normally, against the ordinary stash, and every value they set escapes.
Rules that already contain a STASH LOCAL with ops under it, built before the designer treated it as a leaf or brought in from exported rule JSON, still run those ops inside the copy. Everything below describes what happens in that case.
What the copy does and does not cover¶
The copy is taken when the block is entered, so every value set earlier in the rule is visible inside it.
It is one level deep. That distinction is the whole behaviour of the op:
- Creating a key, overwriting a key or removing a key affects the copy only. When the block ends, the original value is back, including the absence of a key you created.
- Reaching into a value that was already in the stash does not. A list, a hash or a loaded resource is shared with the outer stash rather than duplicated, so appending an entry to a list, setting a field inside a nested block, or changing an attribute on a resource is permanently visible afterwards.
So SET VAR inside the block is contained, and PUSH VAR inside the block is not, because it grows a list the outer stash is still pointing at. The same goes for DELETE hashkey on a top-level key, which is contained, against a change made inside a structure, which is not.
Anything outside the stash is untouched by the scoping. Files written, resources saved, topics changed and notifications sent all happen for real, and a rule called from inside the block shares the copy for its whole run.
Failure and rollback¶
The block traps nothing. An error inside it stops the rule at that op like any other, and the copy is discarded on the way out, so values the block had set are not available to an error handler that sits outside it. Put TRY statement and CATCH statement inside the scope, not around it, when the handler needs those values.
On a rollback pass the rule runs again and the block scopes the rollback ops the same way, which is the usual reason a value set on the way out cannot be found on the way back.
The op writes nothing to the job log. The nested ops log normally under their own names.
Combining with other ops¶
Loop ops already scope their own loop variable. Each pass of FOREACH CI and FOREACH file/item sets the per-pass value, and the previous value comes back when the loop ends. That covers most of what people want this op for.
For everything else, be explicit: give the keys distinctive names, and clear them with DELETE hashkey when the section is finished. It costs one more op and it works in the designer as it stands.
To set a group of values for one section of a rule rather than hide them, see MERGE value INTO stash.
Example¶
A block built before the op became a leaf, kept here to show what the scoping does. work_dir is
private to the block and is back to its old value afterwards, while the entry pushed onto
built_items survives.
STASH LOCAL
SET VAR work_dir = /tmp/foo_build
Run command or local script build in ${work_dir}
PUSH VAR built_items += ${artifact_name}