Using the Matrix Step

JFrog Pipelines Documentation

ft:sourceType
Paligo

The Matrix native step enables your pipeline to repeatedly execute the same set of actions in a variety of configurations and runtime environments, with each variant executing as an independent “steplet.” These steplets can, when configured, execute in parallel on multiple build nodes. On completion of all steplets, Pipelines aggregates the result status, giving the appearance of a single step.

Common use cases for Matrix steps are:

  • Splitting a large test suite into smaller units, and executing them in parallel to reduce total execution time.

  • Testing against multiple values of environment variables or multiple runtime images.

Single Dimension Matrix

The Matrix step is useful for performing the same operation multiple times, but with different settings each time. This could mean pushing the same Docker image to different registries, or executing the same set of unit tests with different test values.

For example, we might want to perform the same test on a completed build with different sets of values for animal, mineral, and vegetable.

animal

mineral

vegetable

Variation 1

dog

copper

carrot

Variation 2

goat

iron

broccoli

Variation 3

lizard

lead

<null>

This example pipeline triggers on any change to the BuildInfo resource produced by another pipeline. The Matrix step performs the same execution actions in parallel steplets, with each using a different set of animal, mineral, and vegetable values from the collection specified in the stepletMultipliers:environmentVariables block.

  - name: Matrix_Single_Pipeline
    steps:     
      - name: matrix_example
        type: Matrix
        stepMode: Bash
        configuration:
          inputResources:
            - name: CompletedBuildInfo
        stepletMultipliers:
          environmentVariables:             # Sets of environment variables for steplets
            - animal:    dog                # - Set 1
              mineral:   copper
              vegetable: carrot
            - animal:    goat               # - Set 2
              mineral:   iron
              vegetable: broccoli
            - animal:    lizard             # - Set 3
              mineral:   lead          
              
        execution:
          onExecute:
            - echo "Executing matrix step on ${steplet_id}"
            - echo "Variation animal = ${animal}, mineral = ${mineral}, vegetable = ${vegetable}"

When successfully executed, the run log of the pipeline shows the set of steplets executed by the Matrix step, along with their individual success status and the set of values used for the Matrix Combination.

image2020-7-16_14-11-7.png

Two-Dimension Matrix

A Matrix step can also perform the same operations in multiple runtime environments. For example, running tests in Java and Javascript, or in different release versions of the same runtime.

This can be done as a single-dimension matrix (performing a single, fixed set of actions in each runtime) or as a two-dimension matrix (performing different actions with different configurations in multiple runtimes).

If we modify the single matrix example above to run in both Java and Javascript runtimes, it will execute in a total of 6 steplets; in 2 runtimes for each of 3 sets of environment variables:

Runtime

Set 1

Set 2

Set 3

java 13.0

dog, copper, carrot

goat, iron, broccoli

lizard, lead, &lt;null&gt;

node 8.17.0

dog, copper, carrot

goat, iron, broccoli

lizard, lead, <null>

Matrix Pipeline Example

The following example pipeline can be found in the JFrog GitHub repository. You can fork this repo to your own GitHub account to try on your own installation of Pipelines.

The two-dimension matrix pipeline provides a simplified example of running tests in modules in different runtime environments. It performs basic functionality tests on four different math operation modules, repeating these tests in different release versions of nodejs.

Resources

The first step of the pipeline will trigger on any change to the example GitHub repo, which also houses the test files. So any change to the tests or the pipeline will trigger a new run of the pipeline.

If you have forked the example, you will need to change the path and integration name as noted in the comments.

resources:
  - name: sample_code
    type: GitRepo
    configuration:
      path: jfrog/jfrog-pipelines-matrix-example      # Change to your own path
      branches:
        include: ^master$
      gitProvider: jfrog_github                       # Change to your own GitHub integration name
PreMatrix Step

The PreMatrix generic step is an optional step for performing preamble operations. It may be used to prepare a build environment for execution of a Matrix step.

Our example PreMatrix step loads the npm package dependencies that will be needed by the steplets.

PreMatrix Example Step

      - name: setup
        type: PreMatrix
        configuration:
          inputResources:
            - name: sample_code
        execution:
          onExecute:
            - echo "Preparing the code base"
            - pushd "${res_sample_code_resourcePath}/app"
            - npm install
            - popd 
            - mkdir -p app
            - cp -r "${res_sample_code_resourcePath}/app/." ./app/
Matrix Step

The Matrix step executes the test cases for each module in multiple versions of the nodejs runtime. The modules are specified as environment variables in stepletMultipliers , which also specifies the runtimes.

Matrix Example Step

      - name: test
        type: Matrix
        stepMode: Bash
        configuration:
          inputSteps:
            - name: setup
        stepletMultipliers:
          environmentVariables:
            - module: mod_1
            - module: mod_2
            - module: mod_3
            - module: mod_4
          runtimes:
            - type: image
              image:
                auto:
                  language: node
                  versions:
                    - 12
            - type: image
              image:
                auto:
                  language: node
                  versions:
                    - 8.17.0                    
        execution:
          onExecute:
            - pushd ./setup/app
            - MODULE="$module" npm run test
            - popd
          onComplete:
            - save_tests ./setup/app/reports
PostMatrix Step

The PostMatrix generic step is an optional step for performing post-execution tasks following a Matrix step.

In the example pipeline, the PostMatrix step aggregates all the test reports.

PostMatrix Step Example

      - name: output
        type: PostMatrix
        configuration:
          inputSteps: 
            - name: test
        execution:
          onExecute:
            - echo "Executing the output step"
            - ls -ltr ./test/setup/app/reports
            - save_tests ./test/setup/app/reports
Results

When the example pipeline is loaded and run, the Matrix step executes eight steplets. The run log for each steplet, including saved test results, can be viewed from the pipeline's run history.

image2020-7-16_14-51-12.png

The run log of the PostMatrix step shows the aggregated results of all steplets.

image2020-7-16_14-55-51.png

Multi-node Matrix

A Matrix step can be configured such that each steplet runs on its own build node in the same node pool. This helps in reducing execution time and ensures efficient use of available resources.

This can be done by setting multiNode to true. Default value is false.

Multi-node Matrix Example

steps:
- name: step_1
  type: Matrix
  stepMode: Bash
  configuration:
    multiNode: true
  stepletMultipliers:
    environmentVariables:
      - foo: foo
      - bar: bar

Multi-node pool Matrix

A Matrix step can be configured such that each steplet executes in parallel on multiple node pools with different operating systems or cloud providers.

This can be done by setting multiNode to true. Default value is false.

Multi-node pool Matrix Example

steps:
- name: step_1
  type: Matrix
  stepMode: Bash
  configuration:
    multiNode: true
  stepletMultipliers:
    nodePools:
      - windows
      - ubuntu_18
      - ubuntu_16
    environmentVariables:
      - foo: foo
      - bar: bar