diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a99fc911..ff7fbed7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -3,118 +3,204 @@ name: CI on: push: workflow_dispatch: + inputs: + build-static: + description: "Build static version of mgconsole" + type: boolean + required: false + default: false + workflow_call: + inputs: + build-static: + description: "Build static version of mgconsole" + type: boolean + required: false + default: false -env: - OFFICIAL: true +run-name: "CI: Build and test mgconsole" jobs: build_and_test_ubuntu: - strategy: - matrix: - platform: [ubuntu-22.04] - mg_version: - - "2.19.0" - runs-on: ${{ matrix.platform }} + name: Build and test mgconsole on Ubuntu + runs-on: ubuntu-latest steps: - - name: Set up and check memgraph download link - run: | - mg_version=${{ matrix.mg_version }} - mg_version_short=${mg_version%%-*} - if [ "${{ env.OFFICIAL }}" = "true" ]; then - mg_url="https://download.memgraph.com/memgraph/v${mg_version}/${{ matrix.platform }}/memgraph_${mg_version_short}-1_amd64.deb" - else - mg_url="https://s3.eu-west-1.amazonaws.com/deps.memgraph.io/memgraph/v${mg_version}/${{ matrix.platform }}/memgraph_${mg_version_short}-1_amd64.deb" - fi - echo "Checking Memgraph download link: $mg_url" - if curl --output /dev/null --silent --head --fail $mg_url; then - echo "Memgraph download link is valid" - echo "MEMGRAPH_DOWNLOAD_LINK=${mg_url}" >> $GITHUB_ENV - else - echo "Memgraph download link is not valid" - exit 1 - fi - - name: Install dependencies (Ubuntu 22.04) - if: matrix.platform == 'ubuntu-22.04' + - name: Pull latest memgraph image run: | - sudo apt install -y git cmake make gcc g++ libssl-dev # mgconsole deps - sudo apt install -y libpython3.10 python3-pip # memgraph deps - mkdir ~/memgraph - curl -L ${{ env.MEMGRAPH_DOWNLOAD_LINK }} > ~/memgraph/memgraph_${{ matrix.mg_version }}-1_amd64.deb - sudo systemctl mask memgraph - sudo dpkg -i ~/memgraph/memgraph_${{ matrix.mg_version }}-1_amd64.deb - - uses: actions/checkout@v4 + docker pull memgraph/memgraph:latest + echo "MEMGRAPH_IMAGE=memgraph/memgraph:latest" >> $GITHUB_ENV + + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + - name: Install and test mgconsole run: | - mkdir build - cd build - cmake .. - make - sudo make install - ctest --verbose + cmake -B build -G Ninja -DMEMGRAPH_USE_DOCKER=ON -DMEMGRAPH_DOCKER_IMAGE=$MEMGRAPH_IMAGE + cmake --build build + sudo cmake --install build + ctest --verbose --test-dir build + - name: Save mgconsole test results if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: "mgconsole_ctest.log" path: build/Testing/Temporary/LastTest.log build_windows_mingw: - runs-on: windows-2022 - strategy: - matrix: - include: [ - { msystem: MINGW64, arch: x86_64 } - ] + name: Build and test mgconsole on Windows + runs-on: windows-latest defaults: run: shell: msys2 {0} steps: - name: Set-up repository - uses: actions/checkout@v4 - - uses: msys2/setup-msys2@v2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - uses: msys2/setup-msys2@4f806de0a5a7294ffabaff804b38a9b435a73bda # v2.30.0 with: - msystem: ${{ matrix.msystem }} + msystem: MINGW64 update: true install: >- git base-devel - mingw-w64-${{ matrix.arch }}-toolchain - mingw-w64-${{ matrix.arch }}-cmake - mingw-w64-${{ matrix.arch }}-openssl + mingw-w64-x86_64-toolchain + mingw-w64-x86_64-cmake + mingw-w64-x86_64-openssl + - name: Build and install mgconsole run: | - mkdir build - cd build - cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release .. - cmake --build . --parallel - make install + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release . + cmake --build build --parallel + cmake --install build + - name: Save mgconsole Windows build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: name: "mgconsole Windows build" path: build/src/mgconsole.exe - build_apple: - strategy: - matrix: - platform: [macos-14] - runs-on: ${{ matrix.platform }} + build_apple_arm64: + name: Build and test mgconsole on Apple ARM64 + runs-on: macos-15 + steps: + - name: Set-up repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + # NOTE: CI can't execute end2end tests because there is no way to run + # Memgraph on CI MacOS machines. + + - name: Install openssl + run: | + brew update + brew install openssl + + - name: Build mgconsole + run: | + cmake -B build -G Ninja -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DCMAKE_BUILD_TYPE=Release . + cmake --build build + sudo cmake --install build + + - name: Save mgconsole MacOS build + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: "mgconsole MacOS build ARM64" + path: build/src/mgconsole + + build_apple_x86_64: + name: Build and test mgconsole on Apple X86_64 + runs-on: macos-15-intel steps: - name: Set-up repository - uses: actions/checkout@v4 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 # NOTE: CI can't execute end2end tests because there is no way to run # Memgraph on CI MacOS machines. + - name: Install openssl run: | brew update brew install openssl + - name: Build mgconsole run: | - mkdir build - cd build - cmake -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DCMAKE_BUILD_TYPE=Release .. - make + cmake -B build -G Ninja -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DCMAKE_BUILD_TYPE=Release . + cmake --build build + sudo cmake --install build + - name: Save mgconsole MacOS build - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 with: - name: "mgconsole MacOS build" + name: "mgconsole MacOS build X86_64" path: build/src/mgconsole + + + build_apple_universal: + needs: [build_apple_arm64, build_apple_x86_64] + name: Build Apple universal binary (ARM64 and X86_64) + runs-on: macos-15 + steps: + - name: Set-up repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Download artifacts Apple ARM64 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: "mgconsole MacOS build ARM64" + path: temp-macos-arm64 + + - name: Download artifacts Apple X86_64 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: "mgconsole MacOS build X86_64" + path: temp-macos-x86_64 + + - name: Organize binaries + run: | + mkdir -p macos + lipo -create temp-macos-arm64/mgconsole temp-macos-x86_64/mgconsole -output macos/mgconsole + + - name: List architecture of the binary + run: | + lipo -info macos/mgconsole + + - name: Save mgconsole MacOS universal build + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: "mgconsole MacOS universal build" + path: macos/mgconsole + + build_and_test_static: + if: ${{ inputs.build-static }} + name: Build and test mgconsole static build + strategy: + fail-fast: false + matrix: + arch: [X64, ARM64] + runs-on: [self-hosted, Linux, "${{ matrix.arch }}" ] + steps: + - uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: build mgconsole static + run: | + ./build-generic-linux.sh + + - name: Save mgconsole static build + uses: actions/upload-artifact@b7c566a772e6b6bfb58ed0dc250532a479d7789f # v6.0.0 + with: + name: "mgconsole static Linux build ${{ matrix.arch }}" + path: build/generic/mgconsole + + - name: Pull latest memgraph image + run: | + docker pull memgraph/memgraph:latest + echo "MEMGRAPH_IMAGE=memgraph/memgraph:latest" >> $GITHUB_ENV + + - name: Test mgconsole static build + run: | + ./tests/test-static.sh --docker $MEMGRAPH_IMAGE + ./tests/test-static.sh --use-ssl --docker $MEMGRAPH_IMAGE + + - name: Cleanup docker images + run: | + docker rmi $MEMGRAPH_IMAGE || true + if [[ "${{ matrix.arch }}" == "X64" ]]; then + docker rmi memgraph/mgbuild:v7_centos-9 || true + elif [[ "${{ matrix.arch }}" == "ARM64" ]]; then + docker rmi memgraph/mgbuild:v7_debian-12-arm || true + fi diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 3932af10..3c0ba3b4 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -1,10 +1,10 @@ -name: Build and Release mgconsole Docker Image +name: Build and Release mgconsole on: workflow_dispatch: inputs: version: - description: "Version of the Docker image to publish." + description: "Version of the mgconsole to publish." required: true default: "0.0.1" force_release: @@ -12,23 +12,35 @@ on: type: boolean required: false default: false + test-release: + description: "Test the release by pushing to test repository" + type: boolean + required: false + default: true + +env: + S3_BUCKET: "${{ github.event.inputs.test-release == 'true' && 'deps.memgraph.io' || 'download.memgraph.com' }}" + S3_BASE_PREFIX: "${{ github.event.inputs.test-release == 'true' && 'mgconsole-test' || 'mgconsole' }}/v${{ github.event.inputs.version }}" + +run-name: Release ${{ github.event.inputs.version }} ${{ github.event.inputs.test-release == 'true' && 'test' || '' }} jobs: build-and-push: + name: Build and push Docker image runs-on: ubuntu-latest env: DOCKER_ORGANIZATION_NAME: memgraph - DOCKER_REPOSITORY_NAME: mgconsole + DOCKER_REPOSITORY_NAME: "${{ github.event.inputs.test-release == 'true' && 'mgconsole-test' || 'mgconsole' }}" steps: - name: Checkout repository - uses: actions/checkout@v2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 - name: Set up Docker Buildx - uses: docker/setup-buildx-action@v2 + uses: docker/setup-buildx-action@8d2750c68a42422c14e847fe6c8ac0403b4cbd6f # v3.12.0 - name: Log in to Docker Hub - uses: docker/login-action@v2 + uses: docker/login-action@c94ce9fb468520275223c153574b00df6fe4bcc9 # v3.7.0 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} @@ -50,7 +62,7 @@ jobs: fi - name: Build and push Docker image - uses: docker/build-push-action@v4 + uses: docker/build-push-action@263435318d21b8e681c14492fe198d362a7d2c83 # v6.18.0 with: context: . push: true @@ -59,7 +71,141 @@ jobs: ${{ env.DOCKER_ORGANIZATION_NAME }}/${{ env.DOCKER_REPOSITORY_NAME }}:latest platforms: linux/amd64,linux/arm64 - - name: Verify Docker image run: | - docker run --rm $DOCKER_ORGANIZATION_NAME/$DOCKER_REPOSITORY_NAME:${{ github.event.inputs.version }} --version \ No newline at end of file + docker run --rm $DOCKER_ORGANIZATION_NAME/$DOCKER_REPOSITORY_NAME:${{ github.event.inputs.version }} --version + + build-binaries: + name: Build binaries + uses: ./.github/workflows/ci.yml + with: + build-static: true + + upload-binaries: + name: Upload binaries + needs: [build-binaries, build-and-push] + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2 + + - name: Login to AWS + uses: aws-actions/configure-aws-credentials@f7b8181755fc1413cd909cbac860d8a76dc848f1 # v6.0.2 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: eu-west-1 + + - name: Download artifacts Linux X64 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: "mgconsole static Linux build X64" + path: temp-linux-x64 + + - name: Download artifacts Linux ARM64 + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: "mgconsole static Linux build ARM64" + path: temp-linux-arm64 + + - name: Download artifacts MacOS + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: "mgconsole MacOS universal build" + path: temp-macos + + - name: Download artifacts Windows + uses: actions/download-artifact@37930b1c2abaa49bbe596cd826c3c89aef350131 # v7.0.0 + with: + name: "mgconsole Windows build" + path: temp-windows + + - name: Organize binaries + run: | + mkdir -p linux-x86_64 linux-aarch64 macos windows + find temp-linux-x64 -name "mgconsole" -type f | head -1 | xargs -I {} cp {} linux-x86_64/mgconsole + find temp-linux-arm64 -name "mgconsole" -type f | head -1 | xargs -I {} cp {} linux-aarch64/mgconsole + find temp-macos -name "mgconsole" -type f | head -1 | xargs -I {} cp {} macos/mgconsole + find temp-windows -name "mgconsole.exe" -type f | head -1 | xargs -I {} cp {} windows/mgconsole.exe + + - name: Upload binaries to S3 + env: + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + run: | + aws s3 cp linux-x86_64/mgconsole s3://${{ env.S3_BUCKET }}/${{ env.S3_BASE_PREFIX }}/linux-x86_64/mgconsole + aws s3 cp linux-aarch64/mgconsole s3://${{ env.S3_BUCKET }}/${{ env.S3_BASE_PREFIX }}/linux-aarch64/mgconsole + aws s3 cp macos/mgconsole s3://${{ env.S3_BUCKET }}/${{ env.S3_BASE_PREFIX }}/macos/mgconsole + aws s3 cp windows/mgconsole.exe s3://${{ env.S3_BUCKET }}/${{ env.S3_BASE_PREFIX }}/windows/mgconsole.exe + + - name: Configure Git + run: | + git config user.name "github-actions" + git config user.email "github-actions@github.com" + + - name: Set tag + run: | + TAG="v${{ github.event.inputs.version }}" + echo "TAG=${TAG}" >> $GITHUB_ENV + git tag $TAG + git push origin $TAG + + # TODO(matt): this action is archived, we should probably find a suitable replacement + - name: Create GitHub Release + id: create_release + uses: actions/create-release@0cb9c9b65d5d1901c1f53e5e66eaf4afd303e70e # v1.1.4 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + tag_name: ${{ env.TAG }} + release_name: "Release ${{ env.TAG }}" + draft: true + prerelease: false + + - name: Compress binaries + run: | + tar -czvf mgconsole-${{ env.TAG }}-linux-x86_64.tar.gz -C linux-x86_64 mgconsole + tar -czvf mgconsole-${{ env.TAG }}-linux-aarch64.tar.gz -C linux-aarch64 mgconsole + tar -czvf mgconsole-${{ env.TAG }}-macos.tar.gz -C macos mgconsole + tar -czvf mgconsole-${{ env.TAG }}-windows.tar.gz -C windows mgconsole.exe + + # TODO(matt): this action is archived, we should probably find a suitable replacement + - name: Upload binaries to Release Linux X64 + uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./mgconsole-${{ env.TAG }}-linux-x86_64.tar.gz + asset_name: mgconsole-${{ env.TAG }}-linux-x86_64.tar.gz + asset_content_type: application/octet-stream + + - name: Upload binaries to Release Linux ARM64 + uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./mgconsole-${{ env.TAG }}-linux-aarch64.tar.gz + asset_name: mgconsole-${{ env.TAG }}-linux-aarch64.tar.gz + asset_content_type: application/octet-stream + + - name: Upload binaries to Release MacOS + uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./mgconsole-${{ env.TAG }}-macos.tar.gz + asset_name: mgconsole-${{ env.TAG }}-macos.tar.gz + asset_content_type: application/octet-stream + + - name: Upload binaries to Release Windows + uses: actions/upload-release-asset@e8f9f06c4b078e705bd2ea027f0926603fc9b4d5 # v1.0.2 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + upload_url: ${{ steps.create_release.outputs.upload_url }} + asset_path: ./mgconsole-${{ env.TAG }}-windows.tar.gz + asset_name: mgconsole-${{ env.TAG }}-windows.tar.gz + asset_content_type: application/octet-stream diff --git a/CMakeLists.txt b/CMakeLists.txt index 7314b941..a81f2e31 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,8 +14,8 @@ # You should have received a copy of the GNU General Public License # along with this program. If not, see . -cmake_minimum_required(VERSION 3.5) -project(mgconsole VERSION 1.4) +cmake_minimum_required(VERSION 3.10) +project(mgconsole VERSION 1.5) include(CTest) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/cmake) @@ -33,11 +33,16 @@ string(TOLOWER "${CMAKE_BUILD_TYPE}" CMAKE_BUILD_TYPE_LOWERCASE) # Enable explicit static linking of SSL because of generic Linux binary. set(MGCONSOLE_STATIC_SSL OFF CACHE STRING "Statically link SSL") -# Set default installation directory to '/usr' +# Set default installation directory if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - # '/usr' is a special case, for more details see: - # https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html#special-cases - set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "install dir" FORCE) + if(APPLE) + # On macOS, use /usr/local as /usr/bin is protected by SIP + set(CMAKE_INSTALL_PREFIX "/usr/local" CACHE PATH "install dir" FORCE) + else() + # '/usr' is a special case, for more details see: + # https://cmake.org/cmake/help/latest/module/GNUInstallDirs.html#special-cases + set(CMAKE_INSTALL_PREFIX "/usr" CACHE PATH "install dir" FORCE) + endif() endif() add_subdirectory(src) diff --git a/Dockerfile b/Dockerfile index 2a3d1a9d..54107c9d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,5 +1,5 @@ -FROM debian:bullseye-slim AS builder +FROM debian:trixie-slim AS builder ENV DEBIAN_FRONTEND=noninteractive @@ -21,7 +21,7 @@ RUN mkdir build && cd build && \ make && \ make install -FROM debian:bullseye-slim +FROM gcr.io/distroless/base-debian13 WORKDIR /mgconsole diff --git a/README.md b/README.md index 5bcdd981..8f8fc85b 100644 --- a/README.md +++ b/README.md @@ -23,7 +23,7 @@ docker run -it memgraph/mgconsole:latest ## Building and installing To build and install mgconsole from source you will need: - - CMake version >= 3.4 + - CMake version >= 3.10 - OpenSSL version >= 1.0.2 - C compiler supporting C11 - C++ compiler supporting C++20 @@ -31,19 +31,19 @@ To build and install mgconsole from source you will need: To install compile dependencies on Debian / Ubuntu: ``` -apt-get install -y git cmake make gcc g++ libssl-dev +apt-get install -y git cmake make gcc g++ libssl-dev ninja-build ``` On RedHat / CentOS / Fedora: ``` -yum install -y git cmake make gcc gcc-c++ openssl-devel libstdc++-static +yum install -y git cmake make gcc gcc-c++ openssl-devel libstdc++-static ninja-build ``` On MacOS, first make sure you have [XCode](https://developer.apple.com/xcode/) and [Homebrew](https://brew.sh) installed. Then, in the terminal, paste: ``` -brew install git cmake make openssl +brew install git cmake make openssl ninja ``` On Windows, you need to install the MSYS2. Just follow the [instructions](https://www.msys2.org), up to step 6. @@ -59,39 +59,31 @@ inside the MSYS2 MINGW64 terminal: pacman -Syu --needed base-devel git mingw-w64-x86_64-toolchain mingw-w64-x86_64-cmake mingw-w64-x86_64-openssl ``` -Once everything is in place, create a build directory inside the source -directory and configure the build by running CMake from it as follows: +Once everything is in place, configure the build by running CMake as follows: * on Linux: ``` -mkdir build -cd build -cmake -DCMAKE_BUILD_TYPE=Release .. +cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release . ``` * on MacOS: ``` -mkdir build -cd build -cmake -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DCMAKE_BUILD_TYPE=Release .. +cmake -B build -G Ninja -DOPENSSL_ROOT_DIR="$(brew --prefix openssl)" -DCMAKE_BUILD_TYPE=Release . ``` * on Windows, from the MSYS2 MINGW64 terminal: ``` -mkdir build -cd build -cmake -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release .. +cmake -B build -G "MinGW Makefiles" -DCMAKE_BUILD_TYPE=Release . ``` -After running CMake, you should see a Makefile in the build directory. Then you -can build the project by running: +After running CMake, you can build the project by running: ``` -make +cmake --build build ``` This will build the `mgconsole` binary. To install it, run: ``` -make install +cmake --install build ``` This will install to system default installation directory. If you want to diff --git a/build-generic-linux.sh b/build-generic-linux.sh index 20a095d8..c12e5502 100755 --- a/build-generic-linux.sh +++ b/build-generic-linux.sh @@ -1,49 +1,53 @@ #!/bin/bash + +set -euo pipefail + SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" PROJECT_ROOT="$SCRIPT_DIR" -docker_name="mgconsole_build_generic_linux" -toolchain_url="https://s3-eu-west-1.amazonaws.com/deps.memgraph.io/toolchain-v4/toolchain-v4-binaries-centos-7-x86_64.tar.gz" -toolchain_tar_gz="$(basename $toolchain_url)" -memgraph_repo="https://github.com/memgraph/memgraph.git" -setup_toolchain_cmd="cd /memgraph/environment/os && \ - ./centos-7.sh check TOOLCHAIN_RUN_DEPS || \ - ./centos-7.sh install TOOLCHAIN_RUN_DEPS" -setup_memgraph_cmd="cd /memgraph/environment/os && \ - ./centos-7.sh check MEMGRAPH_BUILD_DEPS || \ - ./centos-7.sh install MEMGRAPH_BUILD_DEPS" -mgconsole_build_cmd="source /opt/toolchain-v4/activate && \ - mkdir -p /mgconsole/build && cd /mgconsole/build && \ - cmake -DCMAKE_BUILD_TYPE=Release .. && make -j" - -if [ ! "$(docker info)" ]; then - echo "ERROR: Docker is required" - exit 1 -fi +RED='\033[1;31m' +GREEN='\033[1;32m' +YELLOW='\033[1;33m' +RESET='\033[0m' -if [ ! "$(docker ps -q -f name=$docker_name)" ]; then - if [ "$(docker ps -aq -f status=exited -f name=$docker_name)" ]; then - echo "Cleanup of the old exited mgconsole build container..." - docker rm $docker_name +function cleanup() { + status=$? + if [ $status -ne 0 ]; then + COLOUR=$RED + else + COLOUR=$YELLOW fi - docker run -d --network host --name "$docker_name" centos:7 sleep infinity + echo -e "${COLOUR}Cleaning up...${RESET}" + docker stop builder || true + exit $status +} + +ARCH="$(arch)" +if [[ $ARCH == "x86_64" ]]; then + DOCKER_IMAGE="memgraph/mgbuild:v7_centos-9" # libc 2.34 +elif [[ $ARCH == "aarch64" ]]; then + DOCKER_IMAGE="memgraph/mgbuild:v7_debian-12-arm" # libc 2.36 fi -echo "The mgconsole build container is active!" -docker_exec () { - cmd="$1" - docker exec -it "$docker_name" bash -c "$cmd" -} +trap cleanup EXIT ERR + +echo -e "${GREEN}Starting build container...${RESET}" +docker run --rm -d --name builder $DOCKER_IMAGE + +echo -e "${GREEN}Copying mgconsole source code to build container...${RESET}" +docker cp "$PROJECT_ROOT/." builder:/home/mg/mgconsole +docker exec -u root builder bash -c "chown -R mg:mg /home/mg/mgconsole" -docker_exec "mkdir -p /mgconsole" -docker cp -q "$PROJECT_ROOT/." "$docker_name:/mgconsole/" -docker_exec "rm -rf /mgconsole/build/*" -docker_exec "yum install -y wget git" -docker_exec "[ ! -f /$toolchain_tar_gz ] && wget -O /$toolchain_tar_gz $toolchain_url" -docker_exec "[ ! -d /opt/toolchain-v4/ ] && tar -xzf /$toolchain_tar_gz -C /opt" -docker_exec "[ ! -d /memgraph/ ] && git clone $memgraph_repo" -docker_exec "$setup_toolchain_cmd" -docker_exec "$setup_memgraph_cmd" -docker_exec "$mgconsole_build_cmd" +echo -e "${GREEN}Building mgconsole...${RESET}" +docker exec -u mg builder bash -c " + source /opt/toolchain-v7/activate && \ + cd /home/mg/mgconsole && \ + cmake -B build -G Ninja -DCMAKE_BUILD_TYPE=Release -DMGCONSOLE_STATIC_SSL=ON -DCMAKE_INSTALL_PREFIX=/home/mg/mgconsole/build/install . && \ + cmake --build build && \ + cmake --install build" + +echo -e "${GREEN}Saving build...${RESET}" mkdir -p "$PROJECT_ROOT/build/generic" -docker cp -q "$docker_name:/mgconsole/build/src/mgconsole" "$PROJECT_ROOT/build/generic/" +docker cp builder:/home/mg/mgconsole/build/install/bin/mgconsole "$PROJECT_ROOT/build/generic/" + +echo -e "${GREEN}Build complete!${RESET}" diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e56db60b..c45a642f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -58,32 +58,37 @@ endif() # Setup GFlags. The GIT_TAG refers to this build: # https://github.com/gflags/gflags/tree/70c01a642f08734b7bddc9687884844ca117e080, # which is the earliest to support modern cmake. +get_filename_component(GFLAGS_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/gflags" ABSOLUTE) +get_filename_component(GFLAGS_LIB_PATH "${GFLAGS_PREFIX}/lib/libgflags.a" ABSOLUTE) +get_filename_component(GFLAGS_DEBUG_LIB_PATH "${GFLAGS_PREFIX}/lib/libgflags_debug.a" ABSOLUTE) ExternalProject_Add(gflags-proj - PREFIX gflags + PREFIX ${GFLAGS_PREFIX} GIT_REPOSITORY https://github.com/gflags/gflags.git GIT_TAG 70c01a6 CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" "-DCMAKE_CXX_COMPILER=${CMAKE_CXX_COMPILER}" - INSTALL_DIR "${PROJECT_BINARY_DIR}/gflags") + INSTALL_DIR ${GFLAGS_PREFIX} + BUILD_BYPRODUCTS "${GFLAGS_LIB_PATH}" "${GFLAGS_DEBUG_LIB_PATH}") -ExternalProject_Get_Property(gflags-proj install_dir) -set(GFLAGS_ROOT ${install_dir}) +set(GFLAGS_ROOT ${GFLAGS_PREFIX}) set(GFLAGS_INCLUDE_DIRS ${GFLAGS_ROOT}/include) -set(GFLAGS_LIBRARY_PATH ${GFLAGS_ROOT}/lib/libgflags.a) -set(GFLAGS_DEBUG_LIBRARY_PATH ${GFLAGS_ROOT}/lib/libgflags_debug.a) +set(GFLAGS_LIBRARY_PATH ${GFLAGS_LIB_PATH}) +set(GFLAGS_DEBUG_LIBRARY_PATH ${GFLAGS_DEBUG_LIB_PATH}) set(GFLAGS_LIBRARY gflags) add_library(${GFLAGS_LIBRARY} STATIC IMPORTED) target_compile_definitions(${GFLAGS_LIBRARY} INTERFACE GFLAGS_IS_A_DLL=0) set_target_properties(${GFLAGS_LIBRARY} PROPERTIES - IMPORTED_LOCATION ${GFLAGS_LIBRARY_PATH} - IMPORTED_LOCATION_DEBUG ${GFLAGS_DEBUG_LIBRARY_PATH} + IMPORTED_LOCATION "${GFLAGS_LIBRARY_PATH}" + IMPORTED_LOCATION_DEBUG "${GFLAGS_DEBUG_LIBRARY_PATH}" INTERFACE_LINK_LIBRARIES Threads::Threads) add_dependencies(${GFLAGS_LIBRARY} gflags-proj) +get_filename_component(MGCLIENT_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/mgclient" ABSOLUTE) +get_filename_component(MGCLIENT_LIB_PATH "${MGCLIENT_PREFIX}/${MG_INSTALL_LIB_DIR}/libmgclient.a" ABSOLUTE) ExternalProject_Add(mgclient-proj - PREFIX mgclient + PREFIX ${MGCLIENT_PREFIX} GIT_REPOSITORY https://github.com/memgraph/mgclient.git GIT_TAG v1.5.0 CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=" @@ -91,17 +96,17 @@ ExternalProject_Add(mgclient-proj "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}" "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" ${MACOSX_OPENSSL_ROOTDIR_FLAG} - INSTALL_DIR "${PROJECT_BINARY_DIR}/mgclient") + INSTALL_DIR ${MGCLIENT_PREFIX} + BUILD_BYPRODUCTS "${MGCLIENT_LIB_PATH}") -ExternalProject_Get_Property(mgclient-proj install_dir) -set(MGCLIENT_ROOT ${install_dir}) +set(MGCLIENT_ROOT ${MGCLIENT_PREFIX}) set(MGCLIENT_INCLUDE_DIRS ${MGCLIENT_ROOT}/include) -set(MGCLIENT_LIBRARY_PATH ${MGCLIENT_ROOT}/${MG_INSTALL_LIB_DIR}/libmgclient.a) +set(MGCLIENT_LIBRARY_PATH ${MGCLIENT_LIB_PATH}) set(MGCLIENT_LIBRARY mgclient) add_library(${MGCLIENT_LIBRARY} STATIC IMPORTED) set_target_properties(${MGCLIENT_LIBRARY} PROPERTIES - IMPORTED_LOCATION ${MGCLIENT_LIBRARY_PATH} + IMPORTED_LOCATION "${MGCLIENT_LIBRARY_PATH}" INTERFACE_LINK_LIBRARIES Threads::Threads) add_dependencies(${MGCLIENT_LIBRARY} mgclient-proj) diff --git a/src/utils/CMakeLists.txt b/src/utils/CMakeLists.txt index 66dfd4e6..3a0fd788 100644 --- a/src/utils/CMakeLists.txt +++ b/src/utils/CMakeLists.txt @@ -1,5 +1,16 @@ +get_filename_component(REPLXX_PREFIX "${CMAKE_CURRENT_BINARY_DIR}/replxx" ABSOLUTE) + +if(CMAKE_BUILD_TYPE_LOWERCASE STREQUAL "debug") + set(REPLXX_LIB_POSTFIX "-d") +elseif(CMAKE_BUILD_TYPE_LOWERCASE STREQUAL "relwithdebinfo") + set(REPLXX_LIB_POSTFIX "-rd") +else() + set(REPLXX_LIB_POSTFIX "") +endif() + +get_filename_component(REPLXX_LIB_PATH "${REPLXX_PREFIX}/${MG_INSTALL_LIB_DIR}/libreplxx${REPLXX_LIB_POSTFIX}.a" ABSOLUTE) ExternalProject_Add(replxx-proj - PREFIX replxx + PREFIX ${REPLXX_PREFIX} GIT_REPOSITORY https://github.com/AmokHuginnsson/replxx.git GIT_TAG release-0.0.4 CMAKE_ARGS "-DCMAKE_INSTALL_PREFIX=" @@ -8,26 +19,18 @@ ExternalProject_Add(replxx-proj "-DCMAKE_C_COMPILER=${CMAKE_C_COMPILER}" "-DREPLXX_BUILD_EXAMPLES=OFF" "-DBUILD_SHARED_LIBS=OFF" - INSTALL_DIR "${PROJECT_BINARY_DIR}/replxx") - -if(CMAKE_BUILD_TYPE_LOWERCASE STREQUAL "debug") - set(REPLXX_LIB_POSTFIX "-d") -elseif(CMAKE_BUILD_TYPE_LOWERCASE STREQUAL "relwithdebinfo") - set(REPLXX_LIB_POSTFIX "-rd") -else() - set(REPLXX_LIB_POSTFIX "") -endif() + INSTALL_DIR ${REPLXX_PREFIX} + BUILD_BYPRODUCTS "${REPLXX_LIB_PATH}") -ExternalProject_Get_Property(replxx-proj INSTALL_DIR) -set(REPLXX_ROOT ${INSTALL_DIR}) +set(REPLXX_ROOT ${REPLXX_PREFIX}) set(REPLXX_INCLUDE_DIRS ${REPLXX_ROOT}/include) -set(REPLXX_LIBRARY_PATH ${REPLXX_ROOT}/${MG_INSTALL_LIB_DIR}/libreplxx${REPLXX_LIB_POSTFIX}.a) +set(REPLXX_LIBRARY_PATH ${REPLXX_LIB_PATH}) set(REPLXX_LIBRARY replxx) add_library(${REPLXX_LIBRARY} STATIC IMPORTED GLOBAL) target_compile_definitions(${REPLXX_LIBRARY} INTERFACE REPLXX_STATIC) set_target_properties(${REPLXX_LIBRARY} PROPERTIES - IMPORTED_LOCATION ${REPLXX_LIBRARY_PATH}) + IMPORTED_LOCATION "${REPLXX_LIBRARY_PATH}") add_dependencies(${REPLXX_LIBRARY} replxx-proj) add_library(utils STATIC utils.cpp thread_pool.cpp bolt.cpp) diff --git a/tests/input_output/CMakeLists.txt b/tests/input_output/CMakeLists.txt index 1f863109..dc740979 100644 --- a/tests/input_output/CMakeLists.txt +++ b/tests/input_output/CMakeLists.txt @@ -16,11 +16,22 @@ set(MEMGRAPH_PATH "/usr/lib/memgraph/memgraph" CACHE FILEPATH "Path to Memgraph binary for client tests") +set(MEMGRAPH_USE_DOCKER OFF CACHE BOOL + "Use Docker container instead of memgraph binary for tests") +set(MEMGRAPH_DOCKER_IMAGE "memgraph/memgraph" CACHE STRING + "Docker image name to use when MEMGRAPH_USE_DOCKER is enabled") + +# Determine test arguments based on Docker mode +if(MEMGRAPH_USE_DOCKER) + set(MEMGRAPH_TEST_ARGS --docker ${MEMGRAPH_DOCKER_IMAGE}) +else() + set(MEMGRAPH_TEST_ARGS ${MEMGRAPH_PATH}) +endif() add_test(NAME mgconsole-test - COMMAND ./run-tests.sh ${MEMGRAPH_PATH} ${PROJECT_BINARY_DIR}/src/mgconsole + COMMAND ./run-tests.sh ${MEMGRAPH_TEST_ARGS} ${PROJECT_BINARY_DIR}/src/mgconsole WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) add_test(NAME mgconsole-secure-test - COMMAND ./run-tests.sh --use-ssl ${MEMGRAPH_PATH} ${PROJECT_BINARY_DIR}/src/mgconsole + COMMAND ./run-tests.sh --use-ssl ${MEMGRAPH_TEST_ARGS} ${PROJECT_BINARY_DIR}/src/mgconsole WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}) diff --git a/tests/input_output/output_csv/spatial.txt b/tests/input_output/output_csv/spatial.txt index 7c399a55..822cd2ba 100644 --- a/tests/input_output/output_csv/spatial.txt +++ b/tests/input_output/output_csv/spatial.txt @@ -3,6 +3,6 @@ "point" "POINT({ x:1, y:0, srid:4326 })" "point" -"POINT({ x:0, y:1, z:2, srid:9757 })" +"POINT({ x:0, y:1, z:2, srid:9157 })" "point" "POINT({ x:1, y:0, z:2, srid:4979 })" diff --git a/tests/input_output/output_tabular/spatial.txt b/tests/input_output/output_tabular/spatial.txt index df8feac2..d1c02c54 100644 --- a/tests/input_output/output_tabular/spatial.txt +++ b/tests/input_output/output_tabular/spatial.txt @@ -11,7 +11,7 @@ +-------------------------------------+ | point | +-------------------------------------+ -| POINT({ x:0, y:1, z:2, srid:9757 }) | +| POINT({ x:0, y:1, z:2, srid:9157 }) | +-------------------------------------+ +-------------------------------------+ | point | diff --git a/tests/input_output/run-tests.sh b/tests/input_output/run-tests.sh index 7570d531..3b204549 100755 --- a/tests/input_output/run-tests.sh +++ b/tests/input_output/run-tests.sh @@ -31,20 +31,46 @@ function echo_success { printf "\033[1;32m~~ $1 ~~\033[0m\n\n"; } function echo_failure { printf "\033[1;31m~~ $1 ~~\033[0m\n\n"; } use_ssl=false -if [ "$1" == "--use-ssl" ]; then - use_ssl=true - shift -fi +use_docker=false +memgraph_image="memgraph/memgraph" +container_name="" + +# Parse flags +while [[ $# -gt 0 ]]; do + case $1 in + --use-ssl) + use_ssl=true + shift + ;; + --docker) + use_docker=true + shift + ;; + *) + break + ;; + esac +done if [ ! $# -eq 2 ]; then - echo "Usage: $0 [path to memgraph binary] [path to client binary]" + echo "Usage: $0 [--use-ssl] [--docker] [path to memgraph binary or docker image] [path to client binary]" exit 1 fi -# Find memgraph binaries. -if [ ! -x $1 ]; then - echo_failure "memgraph executable not found" - exit 1 +if [ "$use_docker" = true ]; then + memgraph_image=$1 + # Check if docker is available + if ! command -v docker &> /dev/null; then + echo_failure "docker command not found" + exit 1 + fi +else + # Find memgraph binaries. + if [ ! -x $1 ]; then + echo_failure "memgraph executable not found" + exit 1 + fi + memgraph_binary=$(realpath $1) fi # Find mgconsole binaries. @@ -53,7 +79,6 @@ if [ ! -x $2 ]; then exit 1 fi -memgraph_binary=$(realpath $1) client_binary=$(realpath $2) ## Environment setup @@ -83,22 +108,79 @@ fi # Start the memgraph process and wait for it to start. echo_info "Starting memgraph" -$memgraph_binary --bolt-port 7687 \ - --bolt-cert-file=$cert_file \ - --bolt-key-file=$key_file \ - --data-directory=$tmpdir \ - --storage-properties-on-edges=true \ - --storage-snapshot-interval-sec=0 \ - --storage-wal-enabled=false \ - --data-recovery-on-startup=false \ - --storage-snapshot-on-exit=false \ - --telemetry-enabled=false \ - --timezone=UTC \ - --log-file='' & - -pid=$! -wait_for_server 7687 -echo_success "Started memgraph" +if [ "$use_docker" = true ]; then + container_name="mgconsole_test_$$" + # Remove container if it already exists (from a previous failed run) + docker rm -f $container_name > /dev/null 2>&1 + # Also check for any containers using port 7687 + existing_container=$(docker ps -a --filter "publish=7687" --format "{{.Names}}" | grep -v "^$" | head -1) + if [ -n "$existing_container" ]; then + echo_info "Error: Existing container using port 7687: $existing_container" + exit 1 + fi + + docker_args=" -p 7687:7687 -p 7444:7444" + if $use_ssl; then + docker create --name $container_name $docker_args \ + $memgraph_image \ + --bolt-port 7687 \ + --bolt-cert-file=/etc/memgraph/ssl/cert.pem \ + --bolt-key-file=/etc/memgraph/ssl/key.pem \ + --storage-properties-on-edges=true \ + --storage-snapshot-interval-sec=0 \ + --storage-wal-enabled=false \ + --data-recovery-on-startup=false \ + --storage-snapshot-on-exit=false \ + --telemetry-enabled=false \ + --timezone=UTC \ + --log-file='' || exit 1 + echo_info "Copying certificates to container" + # Create the SSL directory and copy certificates before starting + docker cp $cert_file $container_name:/tmp/cert.pem + docker cp $key_file $container_name:/tmp/key.pem + docker start $container_name + # Wait a moment for container to be ready + sleep 1 + # Create directory and copy certificates as root, then fix ownership + docker exec -u root $container_name sh -c "mkdir -p /etc/memgraph/ssl/ && cp /tmp/cert.pem /etc/memgraph/ssl/cert.pem && cp /tmp/key.pem /etc/memgraph/ssl/key.pem && chmod 644 /etc/memgraph/ssl/cert.pem && chmod 600 /etc/memgraph/ssl/key.pem && chown -R memgraph:memgraph /etc/memgraph/ssl/ || true" + docker exec $container_name ls -la /etc/memgraph/ssl/ 2>&1 || true + # Restart container to pick up the certificates + docker restart $container_name + sleep 2 + else + docker run -d --name $container_name $docker_args \ + $memgraph_image \ + --bolt-port 7687 \ + --storage-properties-on-edges=true \ + --storage-snapshot-interval-sec=0 \ + --storage-wal-enabled=false \ + --data-recovery-on-startup=false \ + --storage-snapshot-on-exit=false \ + --telemetry-enabled=false \ + --timezone=UTC \ + --log-file='' || exit 1 + fi + + wait_for_server 7687 + echo_success "Started memgraph in docker container" +else + $memgraph_binary --bolt-port 7687 \ + --bolt-cert-file=$cert_file \ + --bolt-key-file=$key_file \ + --data-directory=$tmpdir \ + --storage-properties-on-edges=true \ + --storage-snapshot-interval-sec=0 \ + --storage-wal-enabled=false \ + --data-recovery-on-startup=false \ + --storage-snapshot-on-exit=false \ + --telemetry-enabled=false \ + --timezone=UTC \ + --log-file='' & + + pid=$! + wait_for_server 7687 + echo_success "Started memgraph" +fi ## Tests @@ -109,7 +191,6 @@ echo_info "Prepare database" echo # Blank line $client_binary $client_flags < ${DIR}/prepare.cypher > $tmpdir/prepare.log - echo_info "Running tests" echo # Blank line @@ -126,7 +207,13 @@ for output_dir in ${DIR}/output_*; do run_flags="$client_flags --output-format=$output_format" echo_info "Running test '$test_name' with $output_format output" - $client_binary $run_flags < $filename > $tmpdir/$test_name + $client_binary $run_flags < $filename > $tmpdir/$test_name 2>&1 + test_exit_code=$? + if [ $test_exit_code -ne 0 ]; then + echo_failure "Test '$test_name' with $output_format output failed with exit code $test_exit_code" + echo "Output:" + cat $tmpdir/$test_name + fi diff -b $tmpdir/$test_name $output_dir/$output_name test_code=$? if [ $test_code -ne 0 ]; then @@ -149,17 +236,27 @@ done ## Cleanup echo_info "Starting test cleanup" -# Shutdown the memgraph process. -kill $pid -wait -n -code_mg=$? +# Shutdown the memgraph process or container. +if [ "$use_docker" = true ]; then + docker stop $container_name > /dev/null 2>&1 + code_mg=$? + docker rm $container_name > /dev/null 2>&1 +else + kill $pid + wait -n + code_mg=$? +fi # Remove temporary directory rm -rf $tmpdir # Check memgraph exit code. if [ $code_mg -ne 0 ]; then - echo_failure "The memgraph process didn't terminate properly!" + if [ "$use_docker" = true ]; then + echo_failure "The memgraph container didn't terminate properly!" + else + echo_failure "The memgraph process didn't terminate properly!" + fi exit $code_mg fi echo_success "Test cleanup done" diff --git a/tests/test-static.sh b/tests/test-static.sh new file mode 100755 index 00000000..a1103cbd --- /dev/null +++ b/tests/test-static.sh @@ -0,0 +1,41 @@ +#!/bin/bash +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" +PROJECT_ROOT="$SCRIPT_DIR/.." + +set -euo pipefail + +# Parse flags +use_ssl=false +use_docker=false +while [[ $# -gt 0 ]]; do + case $1 in + --use-ssl) + use_ssl=true + shift + ;; + --docker) + use_docker=true + shift + ;; + *) + break + ;; + esac +done + +memgraph_image=${1:-"memgraph/memgraph:latest"} +client_binary=${2:-"$PROJECT_ROOT/build/generic/mgconsole"} + +echo "Testing mgconsole static build" +script_args=() +if $use_ssl; then + script_args+=("--use-ssl") +fi +if $use_docker; then + script_args+=("--docker") +fi +script_args+=("$memgraph_image" "$client_binary") + +cd "$SCRIPT_DIR/input_output" +./run-tests.sh "${script_args[@]}" +echo "Tests passed"