Templating & Variables

Template Types

FirmwareCI offers a variety of template groups. These templates are sourced from various origins, such as device-specific information. Each template is identified by a combination of a category identifier and a name identifier, separated by a period (e.g., [[input.Binary]]). The name identifier can include characters from a-z, A-Z, underscores (_), and hyphens (-).

Dynamic Job Input

pre.yaml

pre-stage:
  - cmd: dutctl
    name: Flash the firmware binary.
    parameters:
      host: "my-flasher-address"
      command: flash
      args: [write, "[[input.Binary]]"]

Templates using the [[input.*]] syntax require you to supply the referenced inputs for each job request. These inputs are typically firmware binaries or other dynamic data to be tested with a test run. For example, in the pre.yaml configuration, the [[input.Binary]] placeholder must be provided with the path to the binary you wish to flash.

When submitting a job, ensure that all required inputs referenced in your pre-stage, post-stage, and test files are included. The job will not start unless every referenced input is supplied.

Attributes

Attributes of DUTs can be referenced using attributes.name-of-attribute. Common use-cases include addresses of the target device, the flash device, or flags used in testing tools.

Refer to the DUT Configuration for additional information.

- cmd: ping
   name: Wait for SSH service
   options:
      timeout: 2m
   parameters:
      host: "[[attributes.Host]]"

In this example, attributes.Host specifies the target address for the ping command.

Reservation

Reservation attributes of DUTs can be referenced using reservation.attribute-name. These are typically used for accessing dynamic data provided by external reservation systems, such as UUIDs or dynamically assigned host addresses. An external reservation can be specified in the reservation-system field of your dut.yaml file. When configured, the reservation system may populate various key-value pairs based on its integration.

For more information, please refer to the DUT Configuration documentation.

- cmd: ping
  name: Wait for SSH service
  options:
    timeout: 2m
  parameters:
    host: "[[reservation.DynamicHost]]"

In this example, reservation.DynamicHost references a target address dynamically assigned by the reservation system. This value must be provided by the configured reservation system prior to test execution.

Storage

A storage can be referenced via storage.name-of-storage. Common use-cases include individual tools, which are copied onto the Device Under Test (DUT) for testing purposes. If a storage is referenced inside a test, it is available at the path resolved by the template.

Refer to the storage documentation & the storage guide for additional information.

- cmd: copy
   name: Copy tooling to DUT
   transport: *transport
   parameters:
      source: "[[storage.tool]]/system-suite"
      destination: /root/default-tools/system-suite
      recursive: true

In this example, a directory from the storage system_suite is copied by referencing its parent path using the template storage.tool.

Secrets

Secrets can be referenced via secrets.name-of-secret. Common use-cases include API-Tokens.

Refer to the secrets tutorial for additional information.

name: Binarly Scan
description: Test the firmware with Binarly

#The binarly test works without a DUT, therefore we can leave the pre- & post-stage empty
pre-stage: empty
post-stage: empty

stages:
- name: Binarly Scan
    steps:
    - cmd: binarly report
        name: Binarly Scan
        parameters:
        url: "[[secrets.BinarlyURL]]"
        token: "[[secrets.BinarlyToken]]"
        file_path: "[[input.Binary]]"

In this example multiple secrets are templated from the workflow secrets data.

Defaults

YAML Anchors can be utilized within tests to minimize redundant statements. These anchors should be defined under the defaults keyword in the test file.

Example:

# Boot Test Configuration for ARM-based board
name: Boot Test
description: This test verifies that the ARM-based board boots correctly.

defaults:
  transport: &transport
    proto: ssh
    options:
      host: "[[attributes.Host]]"
      user: root
      password: root

stages:
  - name: Boot Stage
    steps:
      - cmd: ping
        name: Wait for SSH service
        options:
          timeout: 2m
        parameters:
          host: "[[attributes.Host]]"

      - cmd: cmd
        name: Run echo "Hello" on the device
        transport: *transport
        parameters:
          executable: echo
          args: ["Hello"]

      - cmd: cmd
        name: Run echo "World!" on the device
        transport: *transport
        parameters:
          executable: echo
          args: ["World!"]

Variables

Variables enable the storage and reuse of dynamic data within your test workflows. You can define variables globally at the beginning of your test file using the variables key, or assign and update them within individual test steps as the workflow executes. Variables are referenced using the {{ key }} syntax, allowing their current values to be inserted into parameters or other supported fields. This approach facilitates the transfer of data between steps, such as dynamically generated file paths, command outputs, or configuration values, thereby enhancing the flexibility and maintainability of your test definitions.

Example:

variables:
  tmpdir: "/tmp/dir/abc"

stages:
  - name: Example Stage
    steps:
      - cmd: cmd
        name: Create temp dir
        parameters:
          executable: "mktemp"
          args: ["-d", "/tmp/dir/mydir.XXXXXX"]
          variable: "tmpdir"   # Save output to variable 'tmpdir'

      - cmd: cmd
        name: Use temp dir
        parameters:
          executable: "ls"
          args: ["{{ tmpdir }}"]  # Use the value of 'tmpdir' here

In this example, the first step creates a temporary directory and saves its path to the tmpdir variable, which is then used in the next step.