name: 🔬 Test run-name: 🔬 Test ${{ github.sha }} #on: workflow_call on: push: branches: - master - manticore-* paths-ignore: - 'manual/**' - '!manual/References.md' - '.translation-cache/**' - 'cmake/GetGALERA.cmake' - 'galera_packaging/**' pull_request: branches: [ master, update-buddy-version ] paths-ignore: - 'manual/**' - '!manual/References.md' - '.translation-cache/**' - 'cmake/GetGALERA.cmake' - 'galera_packaging/**' types: [opened, synchronize, reopened, labeled, unlabeled] # cancels the previous workflow run when a new one appears in the same branch (e.g. master or a PR's branch) concurrency: group: test_${{ github.ref }} cancel-in-progress: true # Note: Many build jobs skip execution for PRs targeting 'update-buddy-version' branch # as these PRs only update dependency versions and don't require full builds/tests jobs: meta: name: Meta runs-on: ubuntu-22.04 outputs: columnar_locator: ${{ steps.set_locator.outputs.columnar_locator }} branch_name: ${{ steps.check_branch.outputs.branch_name }} branch_tag: ${{ steps.sanitize_branch.outputs.branch_tag }} source_hash: ${{ steps.source_hash.outputs.source_hash }} image_exists: ${{ steps.image_check.outputs.image_exists }} image_tag: ${{ steps.image_check.outputs.image_tag }} image_commit: ${{ steps.image_check.outputs.image_commit }} image_source_hash: ${{ steps.image_check.outputs.image_source_hash }} source: ${{ steps.detect.outputs.source }} test: ${{ steps.detect.outputs.test }} clt: ${{ steps.detect.outputs.clt }} changes_detected: ${{ steps.calc.outputs.changes_detected }} # any relevant change (source/test/clt) skip_builds: ${{ steps.calc.outputs.skip_builds }} # only CLT tests changed and cached test-kit image exists run_builds: ${{ steps.calc.outputs.run_builds }} # build/ubertest jobs run_image_build: ${{ steps.calc.outputs.run_image_build }} # build test-kit image run_clt: ${{ steps.calc.outputs.run_clt }} # run CLT workflow run_image_push: ${{ steps.calc.outputs.run_image_push }} # push test-kit image tags steps: - uses: actions/checkout@v4 with: fetch-depth: 0 - name: Commit info run: | echo "# Automated Tests of commit ${{ github.sha }}" >> $GITHUB_STEP_SUMMARY echo "* Commit URL: [${{ github.sha }}](/${{ github.repository }}/commit/${{ github.sha }})" >> $GITHUB_STEP_SUMMARY echo "* Initiated by: [@${{ github.actor }}](https://github.com/${{ github.actor }})" >> $GITHUB_STEP_SUMMARY echo "* Ref: ${{ github.ref_type }} \"${{ github.ref_name }}\"" >> $GITHUB_STEP_SUMMARY echo "* Attempt: ${{ github.run_attempt }}" >> $GITHUB_STEP_SUMMARY - name: Check if branch exists in manticoresoftware/columnar id: check_branch run: | # Extract the actual branch name for pull requests if [[ "${{ github.event_name }}" == "pull_request" ]]; then BRANCH_NAME="${{ github.event.pull_request.head.ref }}" else BRANCH_NAME="${{ github.ref_name }}" fi HTTP_STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://api.github.com/repos/manticoresoftware/columnar/branches/$BRANCH_NAME) if [ "$HTTP_STATUS" -eq "200" ]; then echo "branch_exists=true" >> $GITHUB_OUTPUT echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT else echo "branch_exists=false" >> $GITHUB_OUTPUT echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT fi - name: Sanitize branch name for tags id: sanitize_branch run: | sanitize_tag() { local name=$1 name=$(echo "$name" | tr '/' '_') name=$(echo "$name" | sed 's/[^a-zA-Z0-9_.-]//g') echo "$name" } branch_name="${{ steps.check_branch.outputs.branch_name }}" branch_tag=$(sanitize_tag "$branch_name") echo "branch_tag=$branch_tag" >> $GITHUB_OUTPUT - name: Calculate source hash id: source_hash run: | set -euo pipefail if [[ "${{ steps.check_branch.outputs.branch_exists }}" == "true" ]]; then git clone --depth 1 --branch "${{ steps.check_branch.outputs.branch_name }}" https://github.com/manticoresoftware/columnar.git columnar rm -rf columnar/.git fi HASH=$(find . -type f ! -path "./test/clt-tests/*" ! -path "./columnar/test/clt-tests/*" ! -path "./.git/*" -print0 | sort -z | xargs -0 md5sum | md5sum | awk '{print $1}') echo "source_hash=$HASH" >> $GITHUB_OUTPUT - name: Check for existing test kit image id: image_check env: REPO_OWNER: ${{ github.repository_owner }} run: | set -euo pipefail TAG="test-kit-${{ steps.sanitize_branch.outputs.branch_tag }}-${{ steps.source_hash.outputs.source_hash }}" if docker manifest inspect "ghcr.io/${REPO_OWNER}/manticoresearch:${TAG}" > /dev/null 2>&1; then echo "image_exists=true" >> $GITHUB_OUTPUT echo "* Reusing cached test-kit image tag: ${TAG}." >> $GITHUB_STEP_SUMMARY docker pull "ghcr.io/${REPO_OWNER}/manticoresearch:${TAG}" > /dev/null image_commit=$(docker inspect -f '{{ index .Config.Labels "org.manticore.testkit.commit" }}' "ghcr.io/${REPO_OWNER}/manticoresearch:${TAG}" || true) image_source_hash=$(docker inspect -f '{{ index .Config.Labels "org.manticore.testkit.source_hash" }}' "ghcr.io/${REPO_OWNER}/manticoresearch:${TAG}" || true) echo "image_commit=${image_commit}" >> $GITHUB_OUTPUT echo "image_source_hash=${image_source_hash}" >> $GITHUB_OUTPUT else echo "image_exists=false" >> $GITHUB_OUTPUT echo "image_commit=" >> $GITHUB_OUTPUT echo "image_source_hash=" >> $GITHUB_OUTPUT fi echo "image_tag=${TAG}" >> $GITHUB_OUTPUT - name: Set Columnar Locator id: set_locator run: | if [[ "${{ github.ref_name }}" != "master" && "${{ steps.check_branch.outputs.branch_exists }}" == "true" ]]; then echo "columnar_locator=GIT_REPOSITORY https://github.com/manticoresoftware/columnar.git GIT_TAG ${{ steps.check_branch.outputs.branch_name }}" >> $GITHUB_OUTPUT else echo "columnar_locator=" >> $GITHUB_OUTPUT fi - name: Detect changed files and categories id: detect shell: bash run: | set -euo pipefail head="${{ github.sha }}" base="" if [[ -n "${{ steps.image_check.outputs.image_commit }}" ]]; then base="${{ steps.image_check.outputs.image_commit }}" elif [[ "${{ github.event_name }}" == "pull_request" ]]; then base="${{ github.event.pull_request.base.sha }}" head="${{ github.event.pull_request.head.sha }}" else base="${{ github.event.before }}" fi files="" if [[ -z "$base" || "$base" == "0000000000000000000000000000000000000000" ]]; then files=$(git ls-tree -r --name-only "$head") else if ! git cat-file -e "$base^{commit}" 2>/dev/null; then git fetch --no-tags --depth=1 origin "$base" fi files=$(git diff --name-only "$base" "$head") fi { echo "### Changed files" echo "* Base: ${base:-'(none)'}" echo "* Head: ${head}" if [[ -n "${{ steps.image_check.outputs.image_commit }}" ]]; then echo "* Using image commit as base" fi } >> "$GITHUB_STEP_SUMMARY" if [[ -z "$files" && "$base" == "$head" ]]; then echo "* No diff (base == head); forcing full run" >> "$GITHUB_STEP_SUMMARY" files="__force_all__" fi if [[ -n "$files" ]]; then echo "$files" | sed 's/^/* /' >> "$GITHUB_STEP_SUMMARY" else echo "* (no files)" >> "$GITHUB_STEP_SUMMARY" fi export FILES="$files" python3 - <<'PY' import os files = os.environ.get("FILES", "").splitlines() source = False test = False clt = False for path in files: if not path: continue if path == "__force_all__": source = True elif path.startswith("test/clt-tests/"): clt = True elif path.startswith("test/"): test = True elif path.startswith(".github/") or path.startswith("manual/") or path.startswith("doc/"): pass else: source = True output = os.environ["GITHUB_OUTPUT"] with open(output, "a", encoding="utf-8") as fh: fh.write(f"source={'true' if source else 'false'}\n") fh.write(f"test={'true' if test else 'false'}\n") fh.write(f"clt={'true' if clt else 'false'}\n") PY - name: Calculate gating id: calc run: | set -euo pipefail changes_detected=false if [[ "${{ steps.detect.outputs.source }}" == "true" || "${{ steps.detect.outputs.test }}" == "true" || "${{ steps.detect.outputs.clt }}" == "true" ]]; then changes_detected=true fi skip_builds=false if [[ "${{ steps.detect.outputs.clt }}" == "true" && "${{ steps.detect.outputs.source }}" != "true" && "${{ steps.detect.outputs.test }}" != "true" && "${{ steps.image_check.outputs.image_exists }}" == "true" ]]; then skip_builds=true fi run_builds=false if [[ "$changes_detected" == "true" && "${{ github.event_name }}" == "pull_request" && "${{ github.event.pull_request.base.ref }}" == "update-buddy-version" ]]; then run_builds=false elif [[ "$changes_detected" == "true" && "$skip_builds" == "false" ]]; then run_builds=true fi run_image_build="$changes_detected" run_clt="$changes_detected" run_image_push=false if [[ "$changes_detected" == "true" && "${{ steps.image_check.outputs.image_exists }}" != "true" ]]; then run_image_push=true fi echo "changes_detected=$changes_detected" >> "$GITHUB_OUTPUT" echo "skip_builds=$skip_builds" >> "$GITHUB_OUTPUT" echo "run_builds=$run_builds" >> "$GITHUB_OUTPUT" echo "run_image_build=$run_image_build" >> "$GITHUB_OUTPUT" echo "run_clt=$run_clt" >> "$GITHUB_OUTPUT" echo "run_image_push=$run_image_push" >> "$GITHUB_OUTPUT" - name: Summarize gating run: | { echo "### Gate decisions" echo "* Changes detected (source/test/CLT): ${{ steps.calc.outputs.changes_detected }}" echo "* Skip builds/ubertests (only CLT changes + cached image): ${{ steps.calc.outputs.skip_builds }}" echo "* Run build/ubertest jobs: ${{ steps.calc.outputs.run_builds }}" echo "* Build test-kit image: ${{ steps.calc.outputs.run_image_build }}" echo "* Run CLT tests: ${{ steps.calc.outputs.run_clt }}" echo "* Push test-kit image tags: ${{ steps.calc.outputs.run_image_push }}" } >> "$GITHUB_STEP_SUMMARY" win_bundle: # Skip build jobs for PRs targeting 'update-buddy-version' branch (buddy version updates don't need full builds) if: needs.meta.outputs.run_builds == 'true' needs: [meta] name: Windows supplementary files preparation runs-on: ubuntu-22.04 steps: - name: Check out cache id: cache uses: actions/cache@v4 with: path: | bundle boost_1_75_0 enableCrossOsArchive: true key: win_bundle lookup-only: true - name: Extract Windows bundle from Windows sysroot if: steps.cache.outputs.cache-hit != 'true' run: | wget https://repo.manticoresearch.com/repository/sysroots/roots_apr15/sysroot_windows_x64.tar.xz tar -xvf sysroot_windows_x64.tar.xz mv diskc/winbundle bundle - name: Extract Boost to put it to the cache if: steps.cache.outputs.cache-hit != 'true' run: | wget https://repo.manticoresearch.com/repository/ci/boost_1_75_0.tgz tar -xf boost_1_75_0.tgz build_linux_debug: if: needs.meta.outputs.run_builds == 'true' needs: [meta] name: Linux debug build uses: ./.github/workflows/build_template.yml with: CTEST_CONFIGURATION_TYPE: "Debug" COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} artifact_name: debug_build cache_key: build_linux_debug_x86_64 cmake_command: | export CMAKE_TOOLCHAIN_FILE=$(pwd)/dist/build_dockers/cross/linux.cmake ctest -VV -S misc/ctest/gltest.cmake --no-compress-output test_linux_debug: if: (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'update-buddy-version') != true name: Linux debug mode tests needs: [build_linux_debug, meta] uses: ./.github/workflows/test_template.yml with: COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} build_artifact_name: debug_build artifact_name: debug_test_results results_name: "Linux debug test results" timeout: 10 build_linux_release: if: needs.meta.outputs.run_builds == 'true' needs: [meta] name: Linux release build uses: ./.github/workflows/build_template.yml with: artifact_name: release_build COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} cache_key: build_linux_release_x86_64 artifact_list: "build/xml build/CMakeFiles/CMake*.log build/api/libsphinxclient/testcli build/src/indexer build/src/indextool build/src/searchd build/src/tests build/src/gtests/gmanticoretest build/config/*.c build/config/*.h build/**/*.cxx build/**/*.gcno build/manticore*deb" cmake_command: | export CMAKE_TOOLCHAIN_FILE=$(pwd)/dist/build_dockers/cross/linux.cmake export PACK=1 export PACK_KEEP_TESTS=1 ctest -VV -S misc/ctest/gltest.cmake --no-compress-output cmake --build build --target package test_linux_release: if: (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'update-buddy-version') != true name: Linux release mode tests needs: [build_linux_release, meta] uses: ./.github/workflows/test_template.yml with: COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} build_artifact_name: release_build artifact_name: release_test_results results_name: "Linux release test results" timeout: 10 # When only CLT changed and a cached image exists, build jobs are skipped. A job that needs # build_linux_release would then be skipped too (GitHub skips dependents of skipped jobs), # so we use a separate reuse-only job that only needs meta. That way CLT always runs when # run_clt is true and we have a test-kit image (either built or reused). test_kit_docker_reuse: name: Test Kit docker image (reuse cache) needs: [meta] if: needs.meta.outputs.run_image_build == 'true' && needs.meta.outputs.image_exists == 'true' runs-on: ubuntu-22.04 steps: - name: Checkout repository # We have to checkout to access .github/workflows/ in further steps uses: actions/checkout@v3 - name: Reuse cached test kit image env: REPO_OWNER: ${{ github.repository_owner }} IMAGE_TAG: ${{ needs.meta.outputs.image_tag }} run: | set -euo pipefail IMAGE="ghcr.io/${REPO_OWNER}/manticoresearch:${IMAGE_TAG}" docker pull "$IMAGE" docker tag "$IMAGE" test-kit:img docker create --name manticore-test-kit-src --entrypoint /bin/sh test-kit:img -c "true" docker export manticore-test-kit-src > manticore_test_kit.img docker rm manticore-test-kit-src - name: Upload docker image artifact uses: manticoresoftware/upload_artifact_with_retries@v4 with: name: manticore_test_kit.img path: manticore_test_kit.img test_kit_docker_build: name: Test Kit docker image needs: - build_linux_release - meta if: needs.meta.outputs.run_image_build == 'true' && needs.meta.outputs.image_exists != 'true' runs-on: ubuntu-22.04 outputs: out-build: ${{ steps.build.outputs.build_image }} steps: - name: Checkout repository # We have to checkout to access .github/workflows/ in further steps uses: actions/checkout@v3 - name: Download built x86_64 Ubuntu Jammy packages uses: manticoresoftware/download_artifact_with_retries@v3 with: name: release_build path: . # Uncomment this shortcut for debug to save time by not preparing the packages in the pack_jammy job # - run: | # wget http://dev2.manticoresearch.com/build_jammy_RelWithDebInfo_x86_64.zip # unzip build_jammy_RelWithDebInfo_x86_64.zip # tar -xvf artifact.tar - name: Calculate short commit hash id: sha run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Building docker id: build run: | BUILD_COMMIT=${{ steps.sha.outputs.sha_short }} /bin/bash dist/test_kit_docker_build.sh echo "build_image=ghcr.io/$REPO_OWNER/manticoresearch:test-kit-${{ steps.sha.outputs.sha_short }}" >> $GITHUB_OUTPUT - name: Upload docker image artifact uses: manticoresoftware/upload_artifact_with_retries@v4 with: name: manticore_test_kit.img path: manticore_test_kit.img clt: if: always() && needs.meta.outputs.run_clt == 'true' && (needs.test_kit_docker_build.result == 'success' || needs.test_kit_docker_reuse.result == 'success') name: CLT needs: [test_kit_docker_build, test_kit_docker_reuse, meta] uses: ./.github/workflows/clt_tests.yml secrets: OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }} VOYAGE_API_KEY: ${{ secrets.VOYAGE_API_KEY }} JINA_API_KEY: ${{ secrets.JINA_API_KEY }} with: docker_image: test-kit:img artifact_name: manticore_test_kit.img repository: ${{ github.repository }} ref: ${{ github.sha }} test_kit_docker_push: if: always() && needs.meta.outputs.run_image_push == 'true' needs: - clt - meta - test_kit_docker_build - test_kit_docker_reuse - test_linux_debug - test_linux_release - test_windows name: Push Test Kit docker image to repo runs-on: ubuntu-22.04 env: GHCR_USER: ${{ vars.GHCR_USER }} GHCR_PASSWORD: ${{ secrets.GHCR_PASSWORD }} REPO_OWNER: ${{ github.repository_owner }} SOURCE_HASH: ${{ needs.meta.outputs.source_hash }} BRANCH_TAG: ${{ needs.meta.outputs.branch_tag }} HASH_TAG_OK: ${{ needs.test_linux_debug.result == 'success' && needs.test_linux_release.result == 'success' && needs.test_windows.result == 'success' }} IMAGE_BUILD_COMMIT: ${{ github.sha }} steps: - name: Checkout repository # We have to checkout to access .github/workflows/ in further steps uses: actions/checkout@v3 - name: Download artifact uses: manticoresoftware/download_artifact_with_retries@main with: name: manticore_test_kit.img path: . - name: Calculate short commit hash id: sha run: echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT - name: Pushing docker image to repo id: test-kit-push run: | TEST_RESULT=${{ needs.clt.result }} BUILD_COMMIT=${{ steps.sha.outputs.sha_short }} /bin/bash dist/test_kit_docker_push.sh build_aarch64: if: needs.meta.outputs.run_builds == 'true' needs: [meta] name: Linux aarch64 build uses: ./.github/workflows/build_template.yml # Use -VV instead of -V below for more verbose output with: arch: aarch64 COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} cmake_command: | mkdir build cd build export CMAKE_TOOLCHAIN_FILE=$(pwd)/../dist/build_dockers/cross/linux.cmake ctest -V -S ../misc/ctest/justbuild.cmake -DCTEST_SOURCE_DIRECTORY=.. --no-compress-output cache_key: build_jammy_aarch64 build_freebsd: if: needs.meta.outputs.run_builds == 'true' needs: [meta] name: FreeBSD x86_64 build uses: ./.github/workflows/build_template.yml with: DISTR: freebsd13 COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} boost_url_key: none cmake_command: | mkdir build cd build export CMAKE_TOOLCHAIN_FILE=$(pwd)/../dist/build_dockers/cross/freebsd.cmake ctest -VV -S ../misc/ctest/justbuild.cmake -DCTEST_SOURCE_DIRECTORY=.. --no-compress-output cache_key: build_freebsd_x86_64 build_windows: if: needs.meta.outputs.run_builds == 'true' needs: [meta] name: Windows x64 build uses: ./.github/workflows/build_template.yml with: DISTR: windows arch: x64 sysroot_url_key: roots_mysql83_jan17 boost_url_key: boost_80 CTEST_CMAKE_GENERATOR: "Ninja Multi-Config" CTEST_CONFIGURATION_TYPE: Debug cache_key: build_windows_x64 artifact_list: "build/xml build/src/Debug/indexer.exe build/src/Debug/indexer.pdb build/src/Debug/searchd.exe build/src/Debug/searchd.pdb build/src/gtests/Debug/gmanticoretest.exe build/src/gtests/Debug/gmanticoretest.pdb build/src/Debug/*.dll build/src/gtests/Debug/*.dll build/config/*.c build/config/*.h" COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} test_windows: if: (github.event_name == 'pull_request' && github.event.pull_request.base.ref == 'update-buddy-version') != true name: Windows tests needs: [build_windows, win_bundle, meta] uses: ./.github/workflows/win_test_template.yml with: CTEST_START: 1 CTEST_END: 999999 COLUMNAR_LOCATOR: ${{ needs.meta.outputs.columnar_locator }} artifact_name: windows_test_results