Call (Embedded Runs)
Embedded runs let you compose and coordinate multiple run definitions. Orchestrating your CI and CD workflows is one situation where this functionality shines.
Like leaves, runs can be embedded using the call
key. Before diving into the details,
let's consider the following example:
on:
github:
push:
if: ${{ event.git.branch == "main" }}
init:
git-ref: ${{ event.git.ref }}
only-at-the-top-level: some-value
tasks:
- key: ci
call: ${{ run.mint-dir }}/ci.yaml
init:
git-ref: ${{ init.git-ref }}
- key: cd
call: ${{ run.mint-dir }}/cd.yaml
after: ci
init:
git-ref: ${{ init.git-ref }}
image-id: ${{ tasks.ci.tasks.build-image.values.image-id }}
There's a lot to consider in this small example. Let's dive in.
call
Runs can be embedded via the call
key. To do so, you can provide a value that starts with ${{ run.mint-dir }}
.
This expression represents the .mint
directory that was present when your run was triggered. Following
${{ run.mint-dir }}
, you provide the filename of the run definition you'd like to embed.
When your run is triggered, either via an event or with the CLI, Mint keeps track of the files in the .mint
directory
and exposes them to you for use in embedded runs.
If you want to embed a run from a definition that is not in the Mint directory, you can reference an artifact produced by a task instead of referencing ${{ run.mint-dir }}
.
init
Rather than providing parameters via with
(like you would in leaves), you use init
for embedded
runs, just like you would if you were configuring a trigger for a run.
Embedded runs only have access to the init
parameters which you explicitly provided. In the example above,
init.only-at-the-top-level
is not available to either embedded run and init.image-id
is only available within the
cd
embedded run.
use
Embedded runs are isolated from one another. They do not share filesystems to ensure that they behave the same way they would
when run in isolation. Because of this, embedded run tasks cannot use
another task and other tasks cannot use
an
embedded run task.
Instead, if you need to share information between embedded runs, you can access subtasks of embedded runs in
expressions. In the example above, the ci
embedded run has a subtask named build-image
which produces an image-id
value. The cd
embedded run can access that value because it runs after ci
. Leaves continue to be encapsulated and
their subtasks are inaccessible (to provide better guarantees around breaking changes in leaves).
after
Even though use
is not permitted with embedded runs, you can still configure order of execution and dependencies via
after
. In the example above, the cd
embedded run will only run after the ci
embedded run has successfully run.
Tool Caches
When using tool caches, embedded runs will not share the same tool cache as the triggered run. Runs should declare their own tool caches to ensure they can run while embedded and in isolation. When a run is embedded, the subtasks of that run respect the tool cache declared in the embedded run's definition.
Concurrency Pools
When your embedded run definition uses a concurrency pool, Mint respects that definition and acquires a lease within that pool prior to starting any tasks within the embedded run.
Dynamic Embedded Runs
Mint supports dynamic embedded runs in addition to referencing another run definition in your .mint
directory. To do so, first run a task that writes a run definition to a file and upload it as an artifact. Then, you can reference that artifact in the call
expression: call: ${{ tasks.generate-run-definition.artifacts.definition }}
. For a full example, take a look at the following tasks:
tasks:
- key: generate-run-definition
run: |
cat << EOF > definition.yml
tasks:
- key: my-embedded-task
run: echo "I'm embedded"
EOF
outputs:
artifacts:
- key: definition
path: definition.yml
- key: embed-dynamic-run
call: ${{ tasks.generate-run-definition.artifacts.definition }}