GitHub CI: update list of container images
[tinc] / .github / workflows / test.yml
index 6c6323c..1757c8e 100644 (file)
@@ -1,5 +1,9 @@
 name: Test
 
+concurrency:
+  group: test-${{ github.head_ref }}
+  cancel-in-progress: true
+
 on:
   push:
   pull_request:
@@ -8,44 +12,147 @@ on:
       - synchronize
 
 jobs:
-  code-style:
-    runs-on: ubuntu-latest
+  cross:
+    runs-on: ubuntu-22.04
+    timeout-minutes: 30
+    strategy:
+      fail-fast: false
+      matrix:
+        arch:
+          - armhf
+          - mipsel
+          - mingw
+
+    container:
+      image: debian:stable
+      options: --privileged
+
     steps:
       - name: Checkout code
-        uses: actions/checkout@v2
+        uses: actions/checkout@v1
+
+      - name: Install deps
+        run: HOST=${{ matrix.arch }} sh .ci/deps.sh
 
-      - name: Install code formatting tools
+      - name: Prepare the system
+        run: HOST=${{ matrix.arch }} sh .ci/test/prepare.sh
+
+      - name: Run tests with default settings
+        run: sudo -u build CI=1 HOST=${{ matrix.arch }} sh .ci/test/run.sh default
+
+      - name: Run tests without legacy protocol
+        run: sudo -u build CI=1 HOST=${{ matrix.arch }} sh .ci/test/run.sh nolegacy
+        if: always()
+
+      - name: Run tests with libgcrypt
+        run: sudo -u build CI=1 HOST=${{ matrix.arch }} sh .ci/test/run.sh gcrypt
+        if: always()
+
+      - name: Upload test results
+        uses: actions/upload-artifact@v2
+        with:
+          name: tests_cross_${{ matrix.arch }}
+          path: /tmp/logs/tests.*.tar.gz
+        if: always()
+
+  muon:
+    runs-on: ubuntu-22.04
+    timeout-minutes: 20
+    container:
+      image: debian:stable-slim
+      env:
+        CI: 1
+
+    steps:
+      - name: Checkout code
+        uses: actions/checkout@v1
+
+      - name: Install dependencies
+        run: SKIP_OPENSSL3=1 SKIP_MESON=1 .ci/deps.sh libpkgconf-dev
+
+      - name: Compatibility with muon
+        run: ./.ci/muon/run.sh
+
+  analysis:
+    runs-on: ubuntu-22.04
+    timeout-minutes: 30
+    steps:
+      - name: Checkout tinc
+        uses: actions/checkout@v3
+        with:
+          fetch-depth: 0
+
+      - name: Install dependencies
+        run: sudo SKIP_OPENSSL3=1 .ci/deps.sh autoconf automake iperf3
+
+      - name: Compatibility with older versions of tinc
+        run: sudo ./.ci/compat/run.sh
+        if: always()
+
+      - name: Install tools
         run: |
-          sudo apt-get install -y astyle
-          curl -OL 'https://github.com/koalaman/shellcheck/releases/download/v0.7.2/shellcheck-v0.7.2.linux.x86_64.tar.xz'
+          sudo apt-get install -y astyle clang-tidy-$CLANG
+          sudo update-alternatives --install /usr/bin/clang-tidy     clang-tidy     /usr/bin/clang-tidy-$CLANG     100
+          sudo update-alternatives --install /usr/bin/run-clang-tidy run-clang-tidy /usr/bin/run-clang-tidy-$CLANG 100
+          curl -OL "https://github.com/koalaman/shellcheck/releases/download/v$SHELLCHECK/shellcheck-v${SHELLCHECK}.linux.x86_64.tar.xz"
           tar -C ~ --strip-components=1 --wildcards -xf ./shellcheck-*.tar.xz 'shellcheck-*/shellcheck'
-          curl -o ~/shfmt -L 'https://github.com/mvdan/sh/releases/download/v3.3.0/shfmt_v3.3.0_linux_amd64'
+          curl -o ~/shfmt -L "https://github.com/mvdan/sh/releases/download/v$SHFMT/shfmt_v${SHFMT}_linux_amd64"
           chmod 755 ~/shfmt ~/shellcheck
+          python3 -m venv /tmp/venv
+          . /tmp/venv/bin/activate
+          pip3 install black pylint mypy markflow
+        env:
+          CLANG: 11
+          SHELLCHECK: 0.8.0
+          SHFMT: 3.5.0
+        if: always()
 
-      - name: Check code formatting
-        run: "! astyle -r --options=.astylerc --dry-run --formatted '*.c' '*.h' | grep '^Formatted'"
+      - name: Lint/typecheck/check formatting on C/shell/Python code
+        run: |
+          . /tmp/venv/bin/activate
+          PATH=$PATH:$HOME ./lint.py
+        if: always()
 
-      - name: Check scripts formatting
-        run: find -type f -regextype egrep -regex '.+\.(sh|sh\.in|test)$' -exec ~/shfmt -d -i 2 -s '{}' +
+      - name: Check warnings (clang)
+        run: bash .ci/warn/run.sh
+        env:
+          CC: clang-12
         if: always()
 
-      - name: Run static analysis on scripts
-        run: find -type f -regextype egrep -regex '.+\.sh(\.in)?$' -exec shellcheck -x '{}' +
+      - name: Check warnings (gcc)
+        run: bash .ci/warn/run.sh
+        env:
+          CC: gcc-11
         if: always()
 
-      - name: Prepare test library and run static analysis on tests
+      - name: Check that very long paths work
         run: |
-          autoreconf -fsi
-          ./configure --disable-{lzo,readline,zlib,curses}
-          find -type f -name '*.test' -execdir shellcheck -x '{}' +
+          meson setup "$WD"
+          meson test -C "$WD" --verbose
+        env:
+          WD: /tmp/tinc_testing_directory_with_a_very_long_path_which_goes_over_the_108_char_limit_on_unix_socket_file_paths
+        if: always()
+
+      - name: Archive test results
+        run: sudo tar -caf tests.tar.gz /usr/local/etc
+        continue-on-error: true
+        if: always()
+
+      - name: Upload test results
+        uses: actions/upload-artifact@v2
+        with:
+          name: tests_compat
+          path: tests.tar.gz
         if: always()
 
   sanitizer:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-22.04
+    timeout-minutes: 30
     strategy:
       fail-fast: false
       matrix:
         sanitizer:
+          - address
           - thread
           - undefined
     env:
@@ -53,255 +160,177 @@ jobs:
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
+        uses: actions/checkout@v1
 
       - name: Install deps
-        shell: bash
-        run: >
-          sudo apt-get install -y
-          git binutils make autoconf automake diffutils texinfo netcat
-          zlib1g-dev lib{ssl,lzo2,ncurses,readline,vdeplug,miniupnpc}-dev
-
-      - name: Configure and compile
-        shell: bash
-        run: bash .github/workflows/sanitizers/build.sh
-        env:
-          CC: clang-12
+        run: |
+          sudo sh .ci/deps.sh iputils-arping
+          sudo pip3 install --upgrade cryptography
 
-      - name: Run tests
-        run: bash .github/workflows/sanitizers/run.sh
+      - name: Run tests with OpenSSL 3
+        run: bash .ci/sanitizers/run.sh openssl3
+        if: always()
 
-      - name: Archive test results
-        run: sudo tar -c -z -f test-results.tar.gz test/ sanitizer/
+      - name: Sanitize tests with default settings
+        run: bash .ci/sanitizers/run.sh default
+        if: always()
+
+      - name: Sanitize tests without legacy protocol
+        run: bash .ci/sanitizers/run.sh nolegacy
+        if: always()
+
+      - name: Run tests with libgcrypt
+        run: bash .ci/sanitizers/run.sh gcrypt
         if: always()
 
       - name: Upload test results
         uses: actions/upload-artifact@v2
         with:
           name: tests_sanitizer_${{ matrix.sanitizer }}
-          path: test-results.tar.gz
+          path: /tmp/logs/tests.*.tar.gz
         if: always()
 
   linux:
-    runs-on: ubuntu-latest
+    runs-on: ubuntu-22.04
+    timeout-minutes: 30
     strategy:
       fail-fast: false
       matrix:
         os:
-          - alpine:3.13
-          - centos:7 # aka RHEL 7
-          - almalinux:8 # aka RHEL 8
+          - alpine:latest
+          - alpine:edge
+          - almalinux:latest
+          - fedora:latest
+          - fedora:rawhide
           - debian:oldstable
           - debian:stable
           - debian:testing
-          - debian:unstable
-          - ubuntu:18.04 # previous LTS
-          - ubuntu:20.04 # current LTS
-          - opensuse/leap # aka SLES
+          - ubuntu:latest
+          - ubuntu:rolling
     container:
       image: ${{ matrix.os }}
       options: --privileged
-
+      env:
+        CI: 1
     steps:
-      - name: Install deps (Alpine)
-        run: >
-          apk add git binutils make autoconf automake gcc linux-headers libtool
-          diffutils texinfo procps openssl-dev zlib-dev lzo-dev ncurses-dev
-          readline-dev musl-dev lz4-dev socat
-        if: startsWith(matrix.os, 'alpine')
-
-      - name: Install deps (Debian and Ubuntu)
-        shell: bash
-        run: |
-          apt-get update
-          apt-get install -y git binutils make autoconf automake gcc diffutils \
-            texinfo netcat procps socat zlib1g-dev lib{ssl,lzo2,lz4,ncurses,readline}-dev
-        env:
-          DEBIAN_FRONTEND: noninteractive
-        if: startsWith(matrix.os, 'debian') || startsWith(matrix.os, 'ubuntu')
-
-      - name: Install deps (RHEL)
-        shell: bash
-        run: |
-          if type dnf 2>/dev/null; then
-            dnf install -y 'dnf-command(config-manager)'
-            dnf config-manager --enable powertools
-          fi
-          yum install -y epel-release
-          yum install -y git binutils make autoconf automake gcc diffutils \
-            texinfo netcat procps socat {lzo,zlib,lz4,ncurses,readline}-devel
-          yum install openssl11-devel || yum install openssl-devel
-        if: startsWith(matrix.os, 'centos') || startsWith(matrix.os, 'alma')
-
-      - name: Install deps (SUSE)
-        shell: bash
-        run: >
-          zypper install -y tar git binutils make autoconf automake gcc procps
-          makeinfo diffutils gzip socat {openssl,zlib,lzo,liblz4,ncurses,readline}-devel
-        if: startsWith(matrix.os, 'opensuse')
-
       - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
+        uses: actions/checkout@v1
+
+      - name: Install deps
+        run: sh .ci/deps.sh
 
       - name: Assign name for test results artifact
-        run: echo TEST_ARTIFACT="$(echo '${{ matrix.os }}' | sed 's|[:/]|_|g')" >>"$GITHUB_ENV"
+        run: echo ARTIFACT="$(echo '${{ matrix.os }}' | sed 's|[:/]|_|g')" >>"$GITHUB_ENV"
+
+      - name: Create a non-privileged user
+        run: sh .ci/test/prepare.sh
+
+      - name: Run tests with OpenSSL 3
+        run: sudo -u build CI=1 sh .ci/test/run.sh openssl3
 
       - name: Run tests with default settings
-        run: sh .github/workflows/test/run.sh default
+        run: sudo -u build CI=1 sh .ci/test/run.sh default
+        if: always()
 
       - name: Run tests without legacy protocol
-        run: sh .github/workflows/test/run.sh nolegacy
+        run: sudo -u build CI=1 sh .ci/test/run.sh nolegacy
+        if: always()
+
+      - name: Run tests with libgcrypt
+        run: sudo -u build CI=1 sh .ci/test/run.sh gcrypt
+        if: always()
 
       - name: Upload test results
         uses: actions/upload-artifact@v2
         with:
-          name: tests_${{ env.TEST_ARTIFACT }}
-          path: /tmp/tests.*.tar.gz
+          name: tests_${{ env.ARTIFACT }}
+          path: /tmp/logs/tests.*.tar.gz
         if: always()
 
-  deb-build:
-    if: startsWith(github.ref, 'refs/tags/release-')
-    needs: linux
-
-    strategy:
-      matrix:
-        os: [ubuntu-18.04, ubuntu-20.04]
-
-    runs-on: ${{ matrix.os }}
-
-    steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-
-      - name: Install build deps
-        run: >
-          sudo apt-get install -y --no-install-{recommends,suggests}
-          devscripts
-          git-buildpackage
-          dh-make
-          texinfo
-          libssl-dev
-          zlib1g-dev
-          liblzo2-dev
-          libncurses-dev
-          libreadline-dev
-          libminiupnpc-dev
-
-      - name: Configure project
-        run: autoreconf -fsi
-
-      - name: Prepare debian directory
-        run: bash .github/workflows/deb/prepare.sh
-        env:
-          JOB_DISTRIBUTION: ${{ matrix.os }}
-
-      - name: Build deb package
-        run: |
-          dpkg-buildpackage -d -us -uc
-          mv ../*.deb .
+      - name: Build package
+        run: sh .ci/package/build.sh
+        if: github.ref == 'refs/heads/1.1' || startsWith(github.ref, 'refs/tags/release-')
+        continue-on-error: true
 
-      - name: Upload packages
+      - name: Upload package
         uses: actions/upload-artifact@v2
         with:
-          name: deb-${{ matrix.os }}
-          path: "*.deb"
-
-  deb-publish:
-    needs: deb-build
-
-    strategy:
-      matrix:
-        os: [ubuntu-18.04, ubuntu-20.04]
-
-    runs-on: ${{ matrix.os }}
+          name: pkg-${{ env.ARTIFACT }}
+          path: |
+            *.deb
+            ~/rpmbuild/RPMS/*/*.rpm
+        continue-on-error: true
+
+  pkg-publish:
+    if: always() && (github.ref == 'refs/heads/1.1' || startsWith(github.ref, 'refs/tags/release-'))
+    runs-on: ubuntu-22.04
+    continue-on-error: true
+    needs:
+      - linux
+      - mingw
 
     steps:
-      - name: Download built packages
+      - name: Create artifact directory
+        run: mkdir -p /tmp/artifacts
+
+      - name: Download packages
         uses: actions/download-artifact@v2
         with:
-          name: deb-${{ matrix.os }}
-
-      - name: Install package
-        run: sudo apt-get install -y ./*.deb
-
-      - name: Prepare tinc configs
-        run: |
-          set -eu
-          sudo mkdir -p /etc/tinc/test/hosts
-          sudo tinc -b -n test generate-ed25519-keys
-          echo "Name test" | sudo tee /etc/tinc/test/tinc.conf
+          path: /tmp/artifacts
 
-      - name: Enable and start tincd
-        run: |
-          sudo systemctl start tinc@test
-          sudo tinc -n test dump reachable nodes
-
-      - name: Publish deb package
+      - name: Publish packages (dev)
+        uses: marvinpinto/action-automatic-releases@latest
+        with:
+          repo_token: ${{ secrets.GITHUB_TOKEN }}
+          automatic_release_tag: latest
+          title: Development release
+          prerelease: true
+          files: /tmp/artifacts/**/*.(deb|rpm|exe)
+        if: startsWith(github.ref, 'refs/heads/')
+
+      - name: Publish packages (release)
         uses: softprops/action-gh-release@v1
         with:
-          files: "*.deb"
-        env:
-          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
+          files: |
+            /tmp/artifacts/**/*.deb
+            /tmp/artifacts/**/*.rpm
+            /tmp/artifacts/**/*.exe
+        if: startsWith(github.ref, 'refs/tags/')
 
   macos:
-    runs-on: macos-latest
-
-    strategy:
-      fail-fast: false
-      matrix:
-        legacy_protocol: ["", --disable-legacy-protocol]
+    runs-on: macos-12
+    timeout-minutes: 20
 
     steps:
       - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
+        uses: actions/checkout@v1
 
       - name: Install build deps
-        run: brew install coreutils netcat automake lzo lz4 miniupnpc
+        run: sh .ci/deps.sh
 
-      - name: Configure project
-        run: |
-          autoreconf -fsi
-          ./configure --with-openssl=/usr/local/opt/openssl@1.1 --enable-{tunemu,miniupnpc} ${{ matrix.legacy_protocol }}
-
-      - name: Compile project
-        run: make -j$(sysctl -n hw.ncpu)
+      - name: Run tests with default settings
+        run: sh .ci/test/run.sh default
 
-      - name: Run tests
-        run: make check-recursive VERBOSE=1
+      - name: Run tests without legacy protocol
+        run: sh .ci/test/run.sh nolegacy
+        if: always()
 
-      - name: Archive test results
-        run: sudo tar -c -z -f test-results.tar.gz test/
+      - name: Run tests with libgcrypt
+        run: sh .ci/test/run.sh gcrypt
         if: always()
 
       - name: Upload test results
         uses: actions/upload-artifact@v2
         with:
-          name: tests_${{ runner.os }}_${{ matrix.legacy_protocol }}
-          path: test-results.tar.gz
+          name: tests_macos
+          path: /tmp/logs/tests.*.tar.gz
         if: always()
 
-  windows:
+  mingw:
     runs-on: windows-latest
-
-    strategy:
-      fail-fast: false
-      matrix:
-        legacy_protocol: ["", --disable-legacy-protocol]
+    timeout-minutes: 30
 
     steps:
-      - name: Checkout code
-        uses: actions/checkout@v2
-        with:
-          fetch-depth: 0
-
       - name: Install msys2
         uses: msys2/setup-msys2@v2
         with:
@@ -309,39 +338,97 @@ jobs:
           # https://packages.msys2.org/package/
           install: >-
             base-devel
+            mingw-w64-x86_64-meson
+            mingw-w64-x86_64-pkgconf
             mingw-w64-x86_64-gcc
             mingw-w64-x86_64-openssl
+            mingw-w64-x86_64-libgcrypt
             mingw-w64-x86_64-zlib
             mingw-w64-x86_64-lzo2
             mingw-w64-x86_64-lz4
             mingw-w64-x86_64-ncurses
             mingw-w64-x86_64-miniupnpc
+            mingw-w64-x86_64-nsis
             git
-            netcat
+            openbsd-netcat
             procps
 
-      - name: Configure project
+      - name: Checkout code
+        uses: actions/checkout@v1
+
+      - name: Run tests with default settings
         shell: msys2 {0}
-        run: |
-          autoreconf -fsi
-          ./configure --enable-miniupnpc --disable-readline --with-curses-include=/mingw64/include/ncurses ${{ matrix.legacy_protocol }}
+        run: sh .ci/test/run.sh default
 
-      - name: Compile project
+      - name: Create installer
         shell: msys2 {0}
-        run: make -j$(nproc)
+        run: sh .ci/package/build.sh
+        if: github.ref == 'refs/heads/1.1' || startsWith(github.ref, 'refs/tags/release-')
+        continue-on-error: true
+
+      - name: Upload package
+        uses: actions/upload-artifact@v2
+        with:
+          name: pkg-windows
+          path: .ci/package/win/tinc-*.exe
+        continue-on-error: true
 
-      - name: Run tests
+      - name: Run tests without legacy protocol
         shell: msys2 {0}
-        run: make check-recursive VERBOSE=1
+        run: sh .ci/test/run.sh nolegacy
+        if: always()
 
-      - name: Archive test results
+      - name: Run tests with libgcrypt
         shell: msys2 {0}
-        run: tar -c -z -f test-results.tar.gz test/
+        run: sh .ci/test/run.sh gcrypt
         if: always()
 
       - name: Upload test results
         uses: actions/upload-artifact@v2
         with:
-          name: tests_${{ runner.os }}_${{ matrix.legacy_protocol }}
-          path: test-results.tar.gz
+          name: tests_windows
+          path: /tmp/logs/tests.*.tar.gz
         if: always()
+
+  msvc:
+    runs-on: windows-latest
+    timeout-minutes: 30
+
+    strategy:
+      fail-fast: false
+      matrix:
+        target:
+          - { build: amd64, host: amd64, test: test }
+          - { build: amd64, host: x86, test: test }
+          - { build: amd64, host: arm64, test: notest }
+
+    env:
+      HOST_ARCH: ${{ matrix.target.host }}
+      BUILD_ARCH: ${{ matrix.target.build }}
+
+    steps:
+      - name: Install meson
+        run: pip3 install meson
+
+      - name: Checkout code
+        uses: actions/checkout@v1
+
+      - name: Activate dev environment
+        uses: ilammy/msvc-dev-cmd@v1
+        with:
+          arch: ${{ matrix.target.build == matrix.target.host && matrix.target.host || format('{0}_{1}', matrix.target.build, matrix.target.host) }}
+
+      - name: Build (nolegacy)
+        run: .ci\windows\build.cmd nolegacy
+
+      - name: Test (nolegacy)
+        run: .ci\windows\test.cmd nolegacy
+        if: always() && matrix.target.test == 'test'
+
+      - name: Build (OpenSSL)
+        run: .ci\windows\build.cmd openssl
+        if: always()
+
+      - name: Test (OpenSSL)
+        run: .ci\windows\test.cmd openssl
+        if: always() && matrix.target.test == 'test'