The ROS build farm

What it can do for me

(And how it does it)

Oct. 9th 2016
Dirk Thomas
ROSCon 2016, Seoul, Korea

build.ros.org



Create easy-to-
install packages

Run tests before /
after code changes

Generate API doc
and meta information

Central Service vs. Distributed

  • You could
    • create Debian packages yourself
    • run the test using e.g. Travis CI
    • generate API documentation yourself

  • But
    • setting up all these processes is quite some effort
      • having someone else do it is great for the users
    • the artifacts should be hosted in a central place
    • if you download "official" binaries you know what you are getting

Central Service But Distributed Repositories

  • A ROS distribution consists of numerous packages
    • various vcs types
    • various hosting services

  • github.com/ros/rosdistro
    • for each ROS distribution
      • target platforms
        e.g. Kinetic: Ubuntu Xenial and Wily,
        Debian Jessie, (Fedora 23 and 24)
      • packages and versions
      • referencing all repositories
    • format of yaml files specified in REP 143

  • To use any of these services
    you need to register your repositories

rosdistro/index.yaml

distributions:
  kinetic:
    distribution:
    - kinetic/distribution.yaml
    distribution_cache: <url .yaml.gz>
            

./kinetic/distribution.yaml

repositories:
  catkin:
    doc: <...>
    release: <...>
    source: <...>

release_platforms:
  ubuntu:
  - wily
  - xenial
            

The High-Level View

  • Get the source code:
    • e.g. git clone
  • Install the required dependencies:
    • using rosdep
  • Build a package:
    • cmake, make, make install
  • Run the tests:
    • make test
  • Create a Debian package:
    • apt-src build
  • Generate documentation
    • rosdoc_lite

Some More Details

  • Need to setup the environment for building
    • Install all dependencies (using binary packages)
    • Since each job has different dependencies
      each job needs to start with a "clean" state
    • Inside a Docker container
  • Build the code from one repository
    • Might contain more than one ROS package
    • The repository is cloned into a catkin workspace
    • Invoke catkin_make_isolated
  • Install the code
    • To check that the install step "works"
  • Build and run the tests
    • Each test produces a xUnit-like result file


One container for multiple packages


Build vs. test dependencies

catkin_make vs. catkin_make_isolated

  • While the Docker container contains the dependencies for all packages
  • Each package is still built "in isolation":
catkin_make catkin_make_isolated
CMake calls 1, for the whole ws N, each pkg separately
Side effects Need to depend on other pkgs targets catkin_EXPORTED_TARGETS
Location of artifacts Merged in a single folder
E.g. one include dir
Each pkg has its own folder
Side effects Package can implicitly access
e.g. the headers from other pkgs
Pros Faster due to higher parallelization Clean separation, better to identify problems



The build farm builds with -j 1 for easily readable output


Create easy-to-
install packages

Run tests before /
after code changes

Generate API doc
and meta information

Devel Jobs

IN: repository check 1h clone Docker #1 install build dep build install Docker #2 install test dep build tests run tests OUT: result CMake / compiler warnings, failing tests OUT: email



rosdistro/kinetic/distribution.yaml

genmsg:
  source:
    type: git
    url: https://github.com/ros/genmsg.git
    version: <valid branch name>
            

pkg/package.xml

<maintainer
  email="dthomas@osrfoundation.org"
>Dirk Thomas</maintainer>
            

+ committers since the job was stable

Pull Request Jobs

IN: repository GitHub webhook clone Docker #1 install build dep build install Docker #2 install test dep build tests run tests OUT: result OUT: email OUT: GitHub PR status


rosdistro/kinetic/distribution.yaml

genmsg:
  source:
    test_pull_request: true
    type: git
    url: https://github.com/ros/genmsg.git
    version: <valid branch name>
              

Pull Request Jobs


Create easy-to-
install packages

Run tests before /
after code changes

Generate API doc
and meta information

Doc Jobs

IN: repository check 3d clone changelog rst → html meta information cross ref index Docker install doc dep generate msg / srv rosdoc_lite ∀ pkgs OUT: result rosdoc_lite warnings OUT: email OUT: generated docs upload to webserver OUT: update cross ref index



rosdistro/kinetic/distribution.yaml

genmsg:
  doc:
    type: git
    url: https://github.com/ros/genmsg.git
    version: <valid branch or tag name>
            

kinetic/api/genmsg/manifest.yaml

api_documentation: \
  http://docs.ros.org/kinetic/api/genmsg/html

description: Generate ROS message and service data.
license: BSD
maintainer_status: maintained
maintainers: Dirk Thomas <email>
authors: <names>

has_changelog_rst: true
depends: <list of package dependencies>
depends_on: <list of packages depending on this>
timestamp: <last generation>

url: http://wiki.ros.org/genmsg
repo_url: https://github.com/ros/genmsg.git
bugtracker: https://github.com/ros/genmsg/issues

devel_jobs: <list of urls>
doc_job: <url>
release_jobs: <list of urls>

actions: <list of action names>
msgs: <list of msg names>
srvs: <list of service names>
            

Wiki Integration


wiki markup

<<PackageHeader(roscpp)>>
            

Create easy-to-
install packages

Run tests before /
after code changes

Generate API doc
and meta information

Release Process

source repository catkin_prepare_release tag version release repository bloom each package, with Debian files Debian source packages source jobs each os name and os code name e.g Ubuntu Xenial Debian binary packages binary jobs each os (code) name and arch e.g Ubuntu Xenial amd64






gbp-repo/tracks.yaml

kinetic:
  devel_branch: master
            

rosdistro/kinetic/distribution.yaml

foo:
  release:
    packages:
    - bar
    - baz
    tags:
      release: release/kinetic/{package}/{version}
    url: https://github.com/ros-gbp/foo-release.git
    version: 1.2.3-4
            

Bloom

source repository on a single branch: - pkgA - pkgB release repository snapshot on sep. branches: pkgA pkgB pkgB package.xml: - build type - build deps - run deps CHANGELOG.rst pkgB e.g. Debian - changelog - control - rules How to build pkg rosdep keys system pkgs rst → custom Each target platform needs custom specialization, e.g. Wily vs. Xenial





AUTOMATION

- Makes releasing as easy as possible
- But allows customization anywhere in the process
- Creates the rosdistro pull request for you
            

Sourcedeb Jobs

IN: release repo check 15min clone specific branch pkg, os (code) name e.g. debian/ros-kinetic-bar-1.2.3-4_xenial Docker install tools debhelper git-buildpackage gbp buildpackage OUT: result OUT: email OUT: Debian source package upload to apt repo OUT: trigger binary jobs ∀ architectures


Binarydeb Jobs

IN: Debian source package triggered by sourcedeb job fetch from apt repo abort ? append timestamp Docker install build dep dpkg-buildpackage OUT: result OUT: email OUT: Debian binary package upload to apt repo OUT: trigger binary jobs ∀ downstream pkgs

Apt Repositories

"main" packages.ros.org/ros/ubuntu Distributed mirrors "testing" packages.ros.org/ros-shadow-fixed/ubuntu manual sync "main" "testing" manual sync "building" newly built pkgs go here auto sync Server colocated with Jenkins Please only use these ones directly



Status Pages

building testing main link to Jenkins job repositories.ros.org/status_page/(ros_kinetic_default.html)

"Decipher" Jenkins Job Names

  • Some example job names
    • Isrc_uS__roscpp__ubuntu_saucy__source
    • Jdev__ros_comm__ubuntu_trusty_amd64
    • Kbin_uX64__rospack__ubuntu_xenial_amd64__binary

    • Until first __: prefix for group of jobs
    • Until next __: the package or repository name
    • Then os name, os code name, arch (except for source jobs),
      source / binary (for release jobs)

Jenkins Statistics - Indigo

count success unstable failure aborted disabled
All 40751 39634 (97.25 %) 148 (0.36 %) 372 (0.91 %) 129 (0.31 %) 456 (1.11 %)
Manage 91 91 (100.00 %) 0 (0.00 %) 0 (0.00 %) 0 (0.00 %) 0 (0.00 %)
Ibin_arm_uThf 2348 1997 (85.05 %) - 16 (0.68 %) 8 (0.34 %) 327 (13.92 %)
Ibin_uS32 2348 2316 (98.63 %) - 22 (0.93 %) 9 (0.38 %) 0 (0.00 %)
Ibin_uS64 2348 2314 (98.55 %) - 22 (0.93 %) 11 (0.46 %) 0 (0.00 %)
Ibin_uT32 2348 2333 (99.36 %) - 12 (0.51 %) 3 (0.12 %) 0 (0.00 %)
Ibin_uT64 2348 2334 (99.40 %) - 11 (0.46 %) 3 (0.12 %) 0 (0.00 %)
Idev 769 645 (83.87 %) 26 (3.38 %) 98 (12.74 %) 0 (0.00 %) 0 (0.00 %)
Idoc 807 756 (93.68 %) 31 (3.84 %) 16 (1.98 %) 1 (0.12 %) 0 (0.00 %)
Ipr 29 20 (68.96 %) 3 (10.34 %) 2 (6.89 %) 0 (0.00 %) 0 (0.00 %)
Isrc_uS 2348 2348 (100.00 %) - 0 (0.00 %) 0 (0.00 %) 0 (0.00 %)
Isrc_uT 2348 2348 (100.00 %) - 0 (0.00 %) 0 (0.00 %) 0 (0.00 %)

Jenkins Statistics - Kinetic

count success unstable failure aborted disabled
All 40751 39634 (97.25 %) 148 (0.36 %) 372 (0.91 %) 129 (0.31 %) 456 (1.11 %)
Manage 91 91 (100.00 %) 0 (0.00 %) 0 (0.00 %) 0 (0.00 %) 0 (0.00 %)
Kbin_dj_dJ64 953 922 (96.74 %) - 15 (1.57 %) 14 (1.46 %) 2 (0.20 %)
Kbin_djv8_dJv8 953 902 (94.64 %) - 17 (1.78 %) 14 (1.46 %) 20 (2.09 %)
Kbin_uW32 953 928 (97.37 %) - 14 (1.46 %) 11 (1.15 %) 0 (0.00 %)
Kbin_uW64 953 928 (97.37 %) - 14 (1.46 %) 11 (1.15 %) 0 (0.00 %)
Kbin_uX32 953 928 (97.37 %) - 14 (1.46 %) 11 (1.15 %) 0 (0.00 %)
Kbin_uX64 953 928 (97.37 %) - 14 (1.46 %) 11 (1.15 %) 0 (0.00 %)
Kbin_uxhf_uXhf 953 905 (94.96 %) - 14 (1.46 %) 11 (1.15 %) 23 (2.41 %)
Kbin_uxhf_uXv8 953 907 (95.17 %) - 15 (1.57 %) 11 (1.15 %) 20 (2.09 %)
Kdev 296 220 (74.32 %) 49 (16.55 %) 27 (9.12 %) 0 (0.00 %) 0 (0.00 %)
Kdoc 310 294 (94.83 %) 11 (3.54 %) 4 (1.29 %) 0 (0.00 %) 0 (0.00 %)
Kpr 30 23 (76.66 %) 2 (6.66 %) 2 (6.66 %) 0 (0.00 %) 0 (0.00 %)
Ksrc_dJ 953 950 (99.68 %) - 0 (0.00 %) 0 (0.00 %) 8 (0.85 %)
Ksrc_uW 953 953 (100.00 %) - 0 (0.00 %) 0 (0.00 %) 0 (0.00 %)
Ksrc_uX 953 953 (100.00 %) - 0 (0.00 %) 0 (0.00 %) 0 (0.00 %)

Resources for Jenkins

  • Hosted at Amazon
    • 1 x Jenkins master (beefy machine)
    • 1 x Webserver
    • 2 x Nodes (always available)
    • N x Nodes (spot instances when necessary)
    •   → $1,000 - $2,000 per month

  • E.g. in September 2016
    • Jenkins ran ~80k builds
    • Which equates to ~10k hours of work

Run "Jobs" Locally

Test Across Multiple Repos

  • ①  You make related changes in different repos, e.g.
    • repo A: add a new API
    • repo B: use the new API
    •   → The devel / PR jobs won't work for this case
      • repo A: passes but doesn't really check the new API
      • repo B: fails because it's using the last released version of A

  • ②  You want to check if your changes break any downstream packages
    • repo A: make some changes
    • repo B: check that the tests for the last released version still pass
    •   → The devel / PR jobs don't cover for this case either

Prerelease "Job"

underlay workspace overlay workspace Selected source repos Dependencies Deps from Debian pkgs Selected overlay repos Implicit overlay repos prerelease.ros.org

Devel job with multiple repos
            

Supported Targets

  • The build farm can produce binary packages for
    • Ubuntu, Debian
    • amd64, i386, arm64, armhf

  • We can't cover all combinations ( and ), for Kinetic we cover
    • Ubuntu: Xenial & Wily amd64 & i386, Xenial arm64 & armhf
    • Debian: Jessie amd64 & arm64

  • Bloom also generates meta information for rpm (Fedora)
    • But we don't build binary packages (yet?)

  • If you want to create binaries for a not supported target
    • Talk to us (<hint> donations as well as time to support efforts helps 😉)
    • Contribute code to automate building binaries for new targets
    • or [see next slide]

Your Own Build Farm

  • Use cases
    • Build a different OS name / OS code name / architecture combination
    • Process private repositories
      • You will need your own rosdistro database
    • Try modified version of the build farm

  • Two step process [wiki.ros.org/buildfarm]
    1. Provision machines:
      • Jenkins master, Apache webserver, Build nodes
    2. Generate the Jenkins jobs

  • Last years presentation from Bosch: [pdf]

   Expect continuous effort

What Can You Do

  • Register your repositories
    • add doc entry to generate documentation
      • create a wiki page for your packages
    • add source entry for devel jobs and easy cloning for users
      • if the devel job fails, don't remove the entry, only disable the job:
        test_commits: false
      • e.g. your repo depends on other packages which are not released
    • consider enabling pull request testing
    • release your packages, also into newer ROS distros

  • Watch out for notification emails from Jenkins
    • read it, search for the problem, try to fix it, ask for help
    • as a last resort: disable the job, blacklist target, remove the release

Troubleshooting

  • "It works locally but the job fails" → something must be different
    • Have you tried using `catkin_make_isolated`?
    • Most commonly you have a dependency installed but the build farm doesn't. Check the declared dependencies.
      CMake Error at /opt/ros/kinetic/share/catkin/cmake/catkinConfig.cmake:83 (find_package):
        Could not find a package configuration file provided by "<pkg_name>"
  • "The devel job passed but the release failed"
    • In a devel job all packages share the same container. One package might declare a dependency another package uses without declaring it itself.
  • Expect (very rarely) all kinds of "hiccups"
    • apt update failing since the repository is being modified concurrently
    • network problems, GitHub resetting the connection, an http request not being handled, ...
    • If your problem persists it's probably not such a hiccup

Questions...


For more information go to:
github.com/ros-infrastructure/ros_buildfarm