# # Copyright (c) 2023 Alan de Freitas # Copyright (c) 2021-2023 Sam Darwin # Copyright (c) 2020-2021 Peter Dimov # Copyright (c) 2021 Andrey Semashev # # Distributed under the Boost Software License, Version 1.0. (See accompanying # file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) # # Official repository: https://github.com/boostorg/url # name: CI on: pull_request: branches: - master - develop - feature/** push: branches: - '*' tags: - "boost-*.*.*" concurrency: group: ${{format('{0}:{1}', github.repository, github.ref)}} cancel-in-progress: true env: GIT_FETCH_JOBS: 8 NET_RETRY_COUNT: 5 DEFAULT_BUILD_VARIANT: debug,release jobs: runner-selection: name: Runner Selection runs-on: ${{ github.repository_owner == 'boostorg' && fromJSON('[ "self-hosted", "linux", "x64", "ubuntu-latest-aws" ]') || 'ubuntu-latest' }} outputs: labelmatrix: ${{ steps.aws_hosted_runners.outputs.labelmatrix }} steps: - name: AWS Hosted Runners id: aws_hosted_runners uses: cppalliance/aws-hosted-runners@v1.0.0 cpp-matrix: needs: [ runner-selection ] runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['ubuntu-latest'] }} name: Generate Test Matrix outputs: matrix: ${{ steps.cpp-matrix.outputs.matrix }} steps: - name: Generate Test Matrix uses: alandefreitas/cpp-actions/cpp-matrix@v1.9.0 id: cpp-matrix with: compilers: | gcc >=5.0 clang >=3.8 msvc >=14.20 apple-clang * mingw * clang-cl * subrange-policy: | msvc: one-per-minor standards: '>=11' latest-factors: | gcc ASan clang Fuzz factors: | gcc UBSan Coverage Shared No-Threads msvc Shared x86 clang ASan UBSan IntSan BoundsSan Time-Trace mingw Shared trace-commands: true build: needs: [ cpp-matrix,runner-selection ] defaults: run: shell: bash strategy: fail-fast: false matrix: include: ${{ fromJSON(needs.cpp-matrix.outputs.matrix) }} name: ${{ matrix.name }} runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.runs-on] }} container: ${{ matrix.container }} env: ${{ matrix.env }} timeout-minutes: 120 steps: # GitHub Actions no longer support older containers. # The workaround is to install our own Node.js for the actions. - name: Patch Node # The containers that need Node.js 20 will have volumes set up so that # the Node.js 20 installation can go there. if: ${{ matrix.container.volumes }} run: | set -x apt-get update apt-get install -y curl xz-utils curl -LO https://archives.boost.io/misc/node/node-v20.9.0-linux-x64-glibc-217.tar.xz tar -xf node-v20.9.0-linux-x64-glibc-217.tar.xz --strip-components 1 -C /node20217 ldd /__e/node20/bin/node - name: Clone Boost.URL uses: actions/checkout@v4 - name: Setup C++ uses: alandefreitas/cpp-actions/setup-cpp@v1.9.0 id: setup-cpp with: compiler: ${{ matrix.compiler }} version: ${{ matrix.version }} - name: Install packages if: matrix.install != '' uses: alandefreitas/cpp-actions/package-install@v1.9.0 id: package-install with: apt-get: ${{ matrix.install }} - name: Clone Boost uses: alandefreitas/cpp-actions/boost-clone@v1.9.0 id: boost-clone with: branch: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }} boost-dir: ../boost-source scan-modules-dir: . scan-modules-ignore: url - name: Setup id: patch shell: bash run: | set -xe # GitHub workspace root workspace_root=$(echo "$GITHUB_WORKSPACE" | sed 's/\\/\//g') echo -E "workspace_root=$workspace_root" >> $GITHUB_OUTPUT # Boost module being tested module=${GITHUB_REPOSITORY#*/} echo "module=$module" >> $GITHUB_OUTPUT # Remove module from Boost source files rm -r "../boost-source/libs/$module" || true # Copy cached Boost source files to an isolated directory mkdir "../boost-root" || true cp -r "../boost-source"/* "../boost-root" # Boost root directory cd "../boost-root" boost_root="$(pwd)" boost_root=$(echo "$boost_root" | sed 's/\\/\//g') echo -E "boost_root=$boost_root" >> $GITHUB_OUTPUT # Patch boost-root with workspace module mkdir "libs/$module" cp -r "$workspace_root"/* "libs/$module" # Set default parameters for CMake workflows as env variables if [ ${{ matrix.compiler }} != "clang-cl" ]; then # We ignore clang-cl because in this case we're using the toolset "-T ClangCL", # which defaults to the clang compiler that comes with Visual Studio. echo 'CC=${{ steps.setup-cpp.outputs.cc || matrix.cc || '' }}' >> $GITHUB_ENV echo 'CXX=${{ steps.setup-cpp.outputs.cxx || matrix.cxx || '' }}' >> $GITHUB_ENV fi echo 'CMAKE_BUILD_TYPE=${{ matrix.build-type || '' }}' >> $GITHUB_ENV echo 'CFLAGS=${{ (matrix.intsan && '-fsanitize=integer -fno-sanitize=unsigned-integer-overflow -fno-sanitize-recover=integer -fno-omit-frame-pointer') || (matrix.boundssan && '-fsanitize=bounds -fno-sanitize-recover=bounds -fno-omit-frame-pointer') || matrix.ccflags || '' }}' >> $GITHUB_ENV echo 'CXXFLAGS=${{ (matrix.intsan && '-fsanitize=integer -fno-sanitize=unsigned-integer-overflow -fno-sanitize-recover=integer -fno-omit-frame-pointer') || (matrix.boundssan && '-fsanitize=bounds -fno-sanitize-recover=bounds -fno-omit-frame-pointer') || matrix.cxxflags || '' }}' >> $GITHUB_ENV echo 'CXXSTD=${{ matrix.latest-cxxstd || '' }}' >> $GITHUB_ENV echo 'BUILD_SHARED_LIB=${{ matrix.shared || '' }}' >> $GITHUB_ENV echo 'BUILD_SHARED_LIBS=${{ matrix.shared || '' }}' >> $GITHUB_ENV echo 'CMAKE_RUN_TESTS=true' >> $GITHUB_ENV echo 'CMAKE_PACKAGE=false' >> $GITHUB_ENV # If windows, check if ml64.exe is available if [ ${{ runner.os }} == "Windows" ]; then if ! command -v ml64.exe &> /dev/null; then echo "ml64.exe not found in PATH." fi fi # Set PATH to find Boost DLLs if [ ${{ matrix.shared }} == "true" ]; then echo "$GITHUB_WORKSPACE/.local/bin" >> $GITHUB_PATH fi - name: Fuzz corpus if: matrix.fuzz uses: actions/cache@v4 id: cache-corpus with: path: ${{ steps.patch.outputs.workspace_root }}/corpus.tar key: corpus-${{ github.run_id }} enableCrossOsArchive: true restore-keys: | corpus- - name: CMake Workflow uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.0 if: matrix.is-no-factor-intermediary != 'true' with: source-dir: ../boost-root build-dir: build_cmake build-target: tests generator: ${{ matrix.generator }} generator-toolset: ${{ matrix.generator-toolset }} install: true install-prefix: .local cmake-version: '>=3.20' extra-args: | -D Boost_VERBOSE=ON -D BOOST_INCLUDE_LIBRARIES=${{ steps.patch.outputs.module }} -D BOOST_URL_DISABLE_THREADS=${{ ( matrix.no-threads && 'ON' ) || 'OFF' }} -D BOOST_URL_BUILD_FUZZERS=${{ ( matrix.fuzz && format('ON -D BOOST_URL_FUZZER_CORPUS_PATH={0}/corpus.tar', steps.patch.outputs.workspace_root) ) || 'OFF' }} -D BOOST_URL_WARNINGS_AS_ERRORS=ON -D TEST_SUITE_SCRIPT_DEBUG=ON export-compile-commands: ${{ matrix.time-trace }} ref-source-dir: ../boost-root/libs/url trace-commands: true - name: CMake Integration Workflow uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.0 if: matrix.is-no-factor-intermediary != 'true' with: source-dir: ../boost-root/libs/${{ steps.patch.outputs.module }}/test/cmake_test build-dir: build_cmake_test generator: ${{ matrix.generator }} generator-toolset: ${{ matrix.generator-toolset }} install: false cmake-version: '>=3.20' extra-args: | 'find_package(Boost)': -D BOOST_CI_INSTALL_TEST=ON -D CMAKE_PREFIX_PATH=${{ steps.patch.outputs.workspace_root }}/.local 'find_package(boost_url)': -D BOOST_CI_INSTALL_MODULE_TEST=ON -D CMAKE_PREFIX_PATH=${{ steps.patch.outputs.workspace_root }}/.local 'add_subdirectory()': -D BOOST_CI_BOOST_SUBDIR_TEST=ON 'add_subdirectory()': -D BOOST_CI_URL_SUBDIR_TEST=ON ref-source-dir: ../boost-root/libs/url trace-commands: true - name: CMake Root Workflow uses: alandefreitas/cpp-actions/cmake-workflow@v1.9.0 if: matrix.is-no-factor-intermediary != 'true' with: source-dir: . build-dir: build_cmake_root generator: ${{ matrix.generator }} generator-toolset: ${{ matrix.generator-toolset }} build-target: tests run-tests: true install: false cmake-version: '>=3.20' extra-args: | -D BOOST_SRC_DIR="../boost-root" -D BOOST_URL_DISABLE_THREADS=${{ ( matrix.no-threads && 'ON' ) || 'OFF' }} -D BOOST_URL_WARNINGS_AS_ERRORS=ON ref-source-dir: . trace-commands: true - name: B2 Workflow uses: alandefreitas/cpp-actions/b2-workflow@v1.9.0 env: # Set flags via B2 options exclusively CFLAGS: '' CXXFLAGS: '' with: source-dir: ../boost-root modules: url toolset: ${{ matrix.b2-toolset }} build-variant: ${{ matrix.build-type }} cxx: ${{ steps.setup-cpp.outputs.cxx || matrix.cxx || '' }} # If this is the latest compiler version in the matrix, we also append `,latest` to `cxxstd` # `latest` is a b2 tag that defaults to the latest C++ standard supported by the compiler, # including experimental ones, decaying to placeholders options (such as 0x, 1y, 1z, 2a, 2b, 2c). cxxstd: ${{ ( matrix.is-latest && ((matrix.cxxstd && format('{0},latest', matrix.cxxstd)) || 'latest' )) || matrix.cxxstd }} address-model: ${{ (matrix.x86 && '32') || '64' }} asan: ${{ matrix.asan }} ubsan: ${{ matrix.ubsan || matrix.intsan }} tsan: ${{ matrix.tsan }} # integer-sanitizer is passed directly as flags ccflags: ${{ (matrix.intsan && '-fsanitize=integer -fno-sanitize=unsigned-integer-overflow -fno-sanitize-recover=integer -fno-omit-frame-pointer') || '' }} cxxflags: ${{ (matrix.intsan && '-fsanitize=integer -fno-sanitize=unsigned-integer-overflow -fno-sanitize-recover=integer -fno-omit-frame-pointer') || '' }} shared: ${{ matrix.shared }} coverage: ${{ matrix.coverage }} define: ${{ (matrix.no-threads && 'BOOST_URL_DISABLE_THREADS') || '' }} warnings-as-errors: true - name: FlameGraph uses: alandefreitas/cpp-actions/flamegraph@v1.9.0 if: matrix.time-trace with: source-dir: ../boost-root/libs/url build-dir: ../boost-root/build_cmake github_token: ${{ secrets.GITHUB_TOKEN }} - name: Codecov if: matrix.coverage env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} run: | set -x if [ -z "$CODECOV_TOKEN" ]; then echo "CODECOV_TOKEN is not set. Skipping coverage report." exit 0 fi # Find gcov gcov_tool="gcov" for version in "${{steps.setup-cpp.outputs.version-major}}.${{steps.setup-cpp.outputs.version-minor}}" "${{steps.setup-cpp.outputs.version-major}}"; do if command -v "gcov-$version" &> /dev/null; then gcov_tool="gcov-$version" break fi done for dir in "../boost-root/build_cmake" "./build_cmake_root" "../boost-root/bin.v2"; do # Generate reports echo "Generate report: $dir" # lcov -c -q -o "$dir/coverage.info" -d "$dir" --include "$(pwd)/../boost-root/libs/${{steps.patch.outputs.module}}/*" --gcov-tool "$gcov_tool" lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 --gcov-tool "$gcov_tool" --directory "$dir" --capture --output-file "$dir/all.info" lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 --list "$dir/all.info" lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 --ignore-errors unused --extract "$dir/all.info" '*/libs/url/*' '*/boost/url*' '*/boost/url.hpp' --output-file "$dir/coverage.info" lcov --rc branch_coverage=0 --rc geninfo_unexecuted_blocks=1 --list "$dir/coverage.info" # Upload to codecov echo "Upload to codecov: $dir" bash <(curl -s https://codecov.io/bash) -f "$dir/coverage.info" done # Summary echo "# Coverage" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "[![codecov](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA/graphs/sunburst.svg)](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Commit: [![codecov](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA/graph/badge.svg)](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Branch: [![codecov](https://codecov.io/github/$GITHUB_REPOSITORY/branch/$GITHUB_REF_NAME/graph/badge.svg)](https://codecov.io/github/$GITHUB_REPOSITORY/commit/$GITHUB_SHA)" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY changelog: needs: [ cpp-matrix,runner-selection ] defaults: run: shell: bash name: Changelog Summary runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)['ubuntu-22.04'] }} timeout-minutes: 120 steps: - name: Clone Boost.URL uses: actions/checkout@v4 with: # Avoid the common API rate limit exceeded error in boostorg by including 100 latest commits in any case fetch-depth: 100 - name: Changelog uses: alandefreitas/cpp-actions/create-changelog@v1.9.0 with: thank-non-regular: ${{ startsWith(github.ref, 'refs/tags/') }} github-token: ${{ secrets.GITHUB_TOKEN }} limit: 200 tag-pattern: 'boost-.+\..+\..+' # Match tags like boost-1.75.0 trace-commands: true antora: needs: [ runner-selection ] strategy: matrix: include: - { name: Windows, os: windows-latest } - { name: Ubuntu, os: ubuntu-latest } - { name: MacOS, os: macos-15 } name: Antora Docs (${{ matrix.name }}) runs-on: ${{ fromJSON(needs.runner-selection.outputs.labelmatrix)[matrix.os] }} defaults: run: shell: bash steps: - name: Install packages uses: alandefreitas/cpp-actions/package-install@v1.9.0 with: apt-get: git cmake - name: Clone Boost.URL uses: actions/checkout@v4 - name: Clone Boost uses: alandefreitas/cpp-actions/boost-clone@v1.9.0 id: boost-clone with: branch: ${{ (github.ref_name == 'master' && github.ref_name) || 'develop' }} boost-dir: ../boost-source scan-modules-dir: . scan-modules-ignore: url - uses: actions/setup-node@v4 with: node-version: 18 - name: Setup Ninja if: runner.os == 'Windows' uses: seanmiddleditch/gha-setup-ninja@v5 - name: Build Antora Docs env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | git config --global --add safe.directory "$(pwd)" cd .. BOOST_SRC_DIR="$(pwd)/boost-source" export BOOST_SRC_DIR cd url cd doc bash ./build_antora.sh # Antora returns zero even if it fails, so we check if the site directory exists if [ ! -d "build/site" ]; then echo "Antora build failed" exit 1 fi - name: Create Antora Docs Artifact uses: actions/upload-artifact@v4 with: name: antora-docs-${{ matrix.name }} path: doc/build/site