Packaging and Testing with Crossbow

The content of arrow/dev/tasks directory aims for automating the process of Arrow packaging and integration testing.

Integration tests:
  • Various docker tests

  • Pandas

  • Dask

  • Turbodbc

  • HDFS

  • Spark



Individual jobs are executed on public CI services, currently:

  • Linux: TravisCI, CircleCI, Azure Pipelines

  • Mac: TravisCI, Azure Pipelines

  • Windows: AppVeyor, Azure Pipelines


Because of the nature of how the CI services work, the scheduling of jobs happens through an additional git repository, which acts like a job queue for the tasks. Anyone can host a queue repository which is usually called as crossbow.

A job is a git commit on a particular git branch, containing only the required configuration file to run the requested build (like .travis.yml, appveyor.yml or azure-pipelines.yml).

Scheduler handles version generation, task rendering and submission. The tasks are defined in tasks.yml.


The following guide depends on GitHub, but theoretically any git server can be used.

  1. Create the queue repository

  2. Enable TravisCI, Appveyor, Azure Pipelines_ and CircleCI integrations on for the newly created queue repository.

  3. Clone the newly created repository next to the arrow repository:

    By default the scripts looks for crossbow next to arrow repository, but this can configured through command line arguments.

    git clone<user>/crossbow crossbow

    Important note: Crossbow only supports GitHub token based authentication. Although it overwrites the repository urls provided with ssh protocol, it’s advisable to use the HTTPS repository URLs.

  4. Create a Personal Access Token with repo permissions (other permissions are not needed)

  5. Locally export the token as an environment variable:

    export CROSSBOW_GITHUB_TOKEN=<token>

    or pass as an argument to the CLI script --github-token

  6. Export the previously created GitHub token on both CI services:

    Use CROSSBOW_GITHUB_TOKEN encrypted environment variable. You can set them at the following URLs, where ghuser is the GitHub username and ghrepo is the GitHub repository name (typically crossbow):

    • TravisCI:<ghuser>/<ghrepo>/settings

    • Appveyor:<ghuser>/<ghrepo>/settings/environment

    • CircleCI:<ghuser>/<ghrepo>/edit#env-vars

    On Appveyor check the skip branches without appveyor.yml checkbox on the web UI under crossbow repository’s settings.

  7. Install Python (minimum supported version is 3.6):

    Miniconda is preferred, see installation instructions:

  8. Install the python dependencies for the script:

    conda install -c conda-forge -y --file arrow/ci/conda_env_crossbow.txt
    # pygit2 requires libgit2:
    pip install \
        jinja2 \
        pygit2 \
        click \
        ruamel.yaml \
        setuptools_scm \ \
        toolz \
  9. Try running it:

    $ python --help


The script does the following:

  1. Detects the current repository, thus supports forks. The following snippet will build kszucs’s fork instead of the upstream apache/arrow repository.

    $ git clone
    $ git clone
    $ cd arrow/dev/tasks
    $ python submit --help  # show the available options
    $ python submit conda-win conda-linux conda-osx
  2. Gets the HEAD commit of the currently checked out branch and generates the version number based on setuptools_scm. So to build a particular branch check out before running the script:

    git checkout ARROW-<ticket number>
    python dev/tasks/ submit --dry-run conda-linux conda-osx

    Note that the arrow branch must be pushed beforehand, because the script will clone the selected branch.

  3. Reads and renders the required build configurations with the parameters substituted.

  4. Create a branch per task, prefixed with the job id. For example to build conda recipes on linux it will create a new branch: crossbow@build-<id>-conda-linux.

  5. Pushes the modified branches to GitHub which triggers the builds. For authentication it uses GitHub OAuth tokens described in the install section.

Query the build status

Build id (which has a corresponding branch in the queue repository) is returned by the submit command.

python status <build id / branch name>

Download the build artifacts

python artifacts <build id / branch name>


Submit command accepts a list of task names and/or a list of task-group names to select which tasks to build.

Run multiple builds:

$ python submit debian-stretch conda-linux-gcc-py37-r40
Commit SHA: 810a718836bb3a8cefc053055600bdcc440e6702
Version: 0.9.1.dev48+g810a7188.d20180414
Pushed branches:
 - debian-stretch
 - conda-linux-gcc-py37-r40

Just render without applying or committing the changes:

$ python submit --dry-run task_name

Run only conda package builds and a Linux one:

$ python submit --group conda centos-7

Run wheel builds:

$ python submit --group wheel

There are multiple task groups in the tasks.yml like docker, integration and cpp-python for running docker based tests.

python submit supports multiple options and arguments, for more see its help page:

$ python submit --help