How to Add More Environments to the Postgres CI

Written by Melih Mutlu
September 30, 2022

This post by Melih Mutlu about the PostgreSQL CI was originally published on the Microsoft TechCommunity Blog.

Have you ever played with Postgres source code and weren't sure if you broke anything? Postgres has a quite comprehensive regression test suite that helps to ensure that nothing is broken. You can, of course, run those tests on your machine and check if your version of Postgres works properly. But it always works on your machine, right? What about other environments?

In this blog post, you will learn about how to enable and use the Postgres CI (plus how to contribute to it!) based on my experience and learnings creating my first patch to Postgres. Specifically, you’ll learn:

  1. How to enable PostgreSQL’s CI for your GitHub fork
  2. How to Build and Test Postgres on Windows in a MinGW environment
  3. How to add a new environment into the PostgreSQL CI

How to enable PostgreSQL’s CI in your GitHub fork

Postgres has a strong reputation for running on multiple different platforms. Therefore, it is important to verify that your code works across these different platforms. That’s where CI tools come in handy. PostgreSQL comes with its own recommended CI: Cirrus CI. You can check and learn about Postgres’s CI and run CI on your fork. Cirrus CI supports Windows, Linux, FreeBSD, and macOS—and allows you to test your changes on those operating systems.

To run tests via Cirrus CI, just follow the below steps:

  1. Fork the PostgreSQL repo on GitHub.
  2. Search Cirrus CI application on GitHub marketplace and add the application to your account.

    screenshot of Cirrus CI app on GitHub marketplace
    Figure 1: Screenshot of the Cirrus CI application on the GitHub marketplace. You can easily set up your free trial and start using Cirrus.
  3. Make sure that Cirrus CI application has access to the Postgres repository you just forked in Step 1.

  4. Cirrus CI is now ready to run. Once you push a commit to your Postgres fork, Cirrus will run CI tasks with your recent commit.

With your new commit, GitHub will show you that CI checks are queued or running.

screenshot of Cirrus CI checks on GitHub
Figure 2: Screenshot of the Cirrus CI checks on GitHub for a commit in Postgres repo after setting up Cirrus CI with the access right to the repo.

You can also view more details by navigating to Cirrus. Here’s what the official Postgres repo on Cirrus CI looks like:

overview of Postgres repo on Cirrus CI
Figure 3: An overview of official Postgres repo looks like on Cirrus CI. You can see the history of your commits and their CI results.

Cirrus CI will show you the results of builds with each commit and upload log files in case of an error.

Now you know what you need to do to benefit from Postgres’ CI. Even if Cirrus CI currently is the one with widest range of OS’es among other Postgres CI’s, the number of supported environments is still limited. Currently only four OS’es are available for Postgres on Cirrus CI. If you need more, you can surely add an environment into the PostgreSQL’s CI via these 2 steps:

  • building Postgres successfully on the target environment
  • adding that environment to Postgres’s CI.

How to Build and Test Postgres on Windows in a MinGW environment

This section explains how to build Postgres on Windows using MinGW. MinGW stands for “Minimal GNU for Windows” and it’s what I chose as a new environment for adding to the Postgres CI. If you’re already familiar with building Postgres on MinGW or your target environment is different, you can skip this section.

If you ever looked into how to build Postgres on Windows, you know that there is more than one way to do it.

  • Use Visual Studio: The most Windows way to build Postgres is using Microsoft Visual Studio. Postgres has already a CI task with Visual Studio.
  • Use MinGW: Another way is to use MinGW on Windows. I personally like using MinGW for Postgres on Windows since it allows you to build Postgres on Windows by using GNU tools. That being the case, the environment added into Postgres’ CI in this post is MinGW.

Using MinGW with MSYS2

If you decide to go with MinGW as well, I recommend installing MSYS2, a tool that provides MinGW environment and many more. MSYS2 comes with tools you might be familiar with from Unix environments and a package manager that allows us to get packages natively built for Windows.

MSYS2 does not give us a single MinGW environment. There are two variants of C standard library available on MSYS2:

  • Microsoft Visual C++ Runtime (MSVCRT). However, even if MSVCRT is also available on Windows, it’s an older library which is not C99 compatible.
  • Universal C Runtime (UCRT). UCRT is an up-to-date version and used by Microsoft Visual Studio by default so that builds by UCRT behave like they are built natively.

If you have MSYS2 ready, you can continue with MinGW with UCRT environment to actually build Postgres from source.

Steps to Build PostgreSQL via MinGW and UCRT

  1. You can run a MinGW with UCRT shell by either searching for “MSYS2 MinGW UCRT x64” on Windows or setting an environment variable named “MSYSTEM” to “UCRT64”. The default MSYS2 environment is determined by the “MSYSTEM” variable if it’s set.
  2. After setting “MSYSTEM”, you can simply launch MinGW with UCRT shell via PowerShell by running:

    $env:MSYSTEM = ‘UCRT64’
    C:\<Path to MSYS installation>\usr\bin\bash.exe -l
    
  3. If you’re launching MinGW for the first time, first update the base packages and databases.

    pacman -Suy
    
  4. Then install the required packages to build Postgres on MinGW.

    pacman -S --needed git bison flex diffutils make \
    ucrt64/mingw-w64-ucrt-x86_64-gcc
    

    You are now done with the MinGW environment setup.

  5. Let’s continue with the installation instructions from Postgres documentation. After this point, the process is like how we would build Postgres on Unix based environments. You need to run configure and make commands and they will do the work.

    ./configure --enable-cassert --enable-debug
    make
    
  6. If all those steps are succeeded, you can run “make check” and see whether everything is okay with your fresh build of Postgres. You may want to enable some of the additional configure options as well. Even though not all those options are available in MinGW, there are some that you can try to build with such as icu, lz4 etc.

    Here is how to install a small subset of Postgres dependencies by running:

    pacman -S ucrt64/mingw-w64-ucrt-x86_64-{icu,libxml2,libxslt,lz4}'
    

    And then change configure command accordingly:

    ./configure --host=x86_64-w64-mingw32 \
    --with-icu --with-libxml --with-libxslt --with-lz4
    

How to add your Environment into the Postgres CI

Now you know how to prepare a MinGW environment, and the steps needed for building Postgres. Wouldn’t it be great if Cirrus CI could do all this work for us? Happily, you can tell Cirrus to run the commands required to build Postgres.

First thing is to let Cirrus know which environment to run on. This environment can be one of those that Cirrus CI provides as default, or Cirrus can use an VM or Docker container image created by users.

You can find the VM and container images that are used by Postgres in pg-vm-images repo. Even though Cirrus CI already provides a Windows container, you might need to install and configure a bunch of different things on your image. In MinGW case, a Windows Docker image which includes MinGW installed as explained in the earlier sections of this blog post was needed. You can find the PR that adds such Windows image

Once your PR preparing your VM or container image is merged, you can move to the next step: adding your scripts to cirrus.yml file. We already have configure and build commands for MinGW builds.

Firstly, you need to create a new task and specify that the new task will use the container you added into pg-vm-images.

task:
  name: Windows - Server 2019, MinGW64
  windows_container:
    image: $CONTAINER_REPO/windows_ci_mingw64:latest

Cirrus has an environment variable called “CIRRUSWORKINGDIR” which is the directory where Cirrus runs. Under this path, specify a “BUILD_DIR” variable as build directory for Postgres.

env:
  BUILD_DIR: "%CIRRUS_WORKING_DIR%/build"

Then you can add your configure, build and test scripts into your new task.

configure_script:
  - C:\msys64\usr\bin\dash.exe -lc "mkdir %BUILD_DIR% &&
    cd %BUILD_DIR% &&
    %CIRRUS_WORKING_DIR%/configure
      --enable-cassert
      --enable-debug
      --with-icu
      --with-libxml
      --with-libxslt
      --with-lz4

build_script:
  C:\msys64\usr\bin\dash.exe -lc "cd %BUILD_DIR% && make world-bin"

tests_script:
  - C:\msys64\usr\bin\dash.exe -lc "cd %BUILD_DIR% && make check-world TMPDIR=%BUILD_DIR%/tmp_install"

Finally, you might want to add an “on_failure” instruction to tell what to do in case of a failure. You can simply call existing “on_failure_ac” configuration for a task uses Autoconf.

on_failure:
  <<: *on_failure_ac

After all these steps, you can now commit and push your changes on cirrus.yml file. Cirrus CI will recognize your new task with MinGW. You should see the new MinGW task will be running on Cirrus CI.

CI tasks running on Cirrus CI
Figure 4: CI tasks running on Cirrus CI, including recently added MinGW task.

And Cirrus will also show all steps needed to run MinGW task and their logs.

Using and contributing to the Postgres CI makes all our PG developer lives easier

This work of adding MinGW into to Postgres’ CI is turned out to be my first patch to Postgres. (It’s not yet committed but it’s in the process of being reviewed.) You can check the patch out to see more about how to add a new task into the CI.

This blog post shows you how to use and contribute to the CI for Postgres, and how to build Postgres using MinGW. Enabling Cirrus CI for your fork will help you see your test results against your changes for Postgres. And contributing to the Postgres CI is a good way to make Postgres better, especially if you need more environments or operating systems than are already there.

Melih Mutlu

Written by Melih Mutlu

Postgres open source engineer at Microsoft. MSc in natural language processing. Speaker at PyCon & PGConf EU. Loves to hack on Postgres, cook & play football (not the American kind!)