Skip to content

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.

STASH LOCAL copies the stash change something nested inside a list or a hash set or delete a top-level key the rule still sees it gone when the block ends the copy is one level deep, so only the top level is private

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}