Skip to content

Latest commit

 

History

History
124 lines (97 loc) · 7.42 KB

File metadata and controls

124 lines (97 loc) · 7.42 KB

Understanding the CI/CD workflows

Note

At the moment, this workflow does not build for the ARM architecture. Please build these locally until Microsoft releases the feature for private repositories. source one, source two. For now, Jetson builds done online will simply be skipped.

Desired behaviour

  1. The user creates a new branch for their changes.
  2. The user commits their changes to the branch, with a relevant tag.
  3. The user pushes the branch to the remote repository.
  4. The CI/CD system detects the new tag and starts building the image.
  5. If the build is successful, the image is pushed to the GitHub Container Registry.
  6. The user can then pull the image from the registry and use it.

Key features

  • Dependant images are built in the correct order.
  • Images are built with the correct tags.
  • The CI/CD system is triggered by tags, not pushes to branches or pull requests.
  • Upon any failure, the system will exit gracefully and not proceed with downstream dependant builds.

Overview of the main workflow

This is a high-level understanding of the workflow described in build.yaml.

  1. The workflow is triggered when a tag starting with v (or dev) is pushed to the repository.

  2. Next, the workflow looks for the Git tag. If it finds a tag that starts with v/dev, records this to a variable, so that it may be used later in the workflow.

  3. The remainder of the build is split into five sections, which run in three steps (some sections run in parallel):

    Step Sections that run in parallel
    1 - ROS2 base humble images (AMD64/x86)
    - ROS2 base humble images (Jetson/ARM)
    2 - ROS2 humble_harmonic (AMD64/x86)
    3 - ROS2 wheelchair2_base images (AMD64/x86)
    - ROS2 wheelchair2_base_jetson (depends on humble_jetson)

    By default, all of these sections are configured as matrix strategies. Although some sections have only one entry, this allows for easy expansion in the future.

Overview of the reusable workflow

It quickly became evident that several steps in the workflow were repetitive, so the majority of the actual work was refactored into a reusable workflow. This is described in build-workflow.yaml, and is briefly explained below.

This workflow is triggered by the main workflow, and receives the following inputs:

Input Description Default
build_context The build context for the Dockerfile -
image_name The target name of the image to build -
image_version The version tag of the image to build -
runs_on The GitHub runner to use for the build ubuntu-latest

First, code is checked out, buildx is setup, and GHCR is authenticated.

Finally, the actual image is built and (if successful) pushed to the GitHub Container Registry, using the docker/build-push-action action.

Deeper dive into the main workflow

Here, we discuss only the potentially confusing parts of the main workflow, which is described in build.yaml.

You are encouraged to read the GitHub Actions documentation for more information on how GitHub Actions work, how to write workflows, and reference for syntax. If you use VS Code to write workflows, the GitHub Actions extension is useful.

Check conditions and set variables

We only trigger the workflow on the push of certain tags:

on:
  push:
    tags:
      - 'dev*'
      - 'v*'

Setting the image version

This simply involves obtaining the Git tag and setting it as an environment variable for later use:

- name: Set image version
  id: set_version
  run: |
    echo "image_version=${{ github.ref_name }}" >> $GITHUB_OUTPUT

Building the images

While there are several sections as described earlier, we shall dive deeper into one of these as exposition. Consider the "Stage 3: ROS2 wheelchair2_base images (AMD64/x86)" section.

# Stage 3: ROS2 wheelchair2_base images (AMD64/x86)
ros2-wheelchair-base:
  needs: [changes, ros2-humble-base-amd64, ros2-humble-harmonic]
  name: ROS2 Wheelchair2 Base Images
  permissions:
    packages: write
    contents: read
  strategy:
    matrix:
      config:
        - { build_context: './ROS2/AMD64x86/wheelchair2_base', image_name: 'wheelchair2_base', image_version: "${{ needs.changes.outputs.image_version }}" }
        - { build_context: './ROS2/AMD64x86/wheelchair2_base_gazebo', image_name: 'wheelchair2_base_gazebo', image_version: "${{ needs.changes.outputs.image_version }}" }
  uses: ./.github/workflows/build-workflow.yaml
  with:
    build_context: ${{ matrix.config.build_context }}
    image_name: ${{ matrix.config.image_name }}
    image_version: ${{ matrix.config.image_version }}
    runs_on: ubuntu-latest

Let's break this down:

  • needs: This job depends on the changes job and the ros2-humble-base-amd64 and ros2-humble-harmonic jobs. It will only run if these jobs are successful. This ensures that dependant images are built in the correct order.
  • permissions: This job requires write access to packages (to push the built images) and read access to contents (to read the repository).
  • strategy: This defines a matrix strategy for the job. In this case, we have two configurations:
    • wheelchair2_base: The base image for the wheelchair2 project.
    • wheelchair2_base_gazebo: The base image for the wheelchair2 project with Gazebo support.
  • uses: This specifies that the job will use the reusable workflow defined in build-workflow.yaml.
  • with: This passes the necessary parameters to the reusable workflow, including the build context, image name, image version, and the runner to use.

Note the matrix system:

strategy:
  matrix:
    config:
      - { build_context: './ROS2/AMD64x86/wheelchair2_base', image_name: 'wheelchair2_base', image_version: "${{ needs.changes.outputs.image_version }}" }
      - { build_context: './ROS2/AMD64x86/wheelchair2_base_gazebo', image_name: 'wheelchair2_base_gazebo', image_version: "${{ needs.changes.outputs.image_version }}" }

In this system, we specify one or more configurations for the job. Each configuration corresponds to one resulting image. The reusable workflow will be run for each configuration, allowing us to build multiple images in parallel by just adding one more entry to the config list.

Please consult the GitHub Actions documentation for more information on matrix strategies and syntax.