diff --git a/.ci/compile.sh b/.ci/compile.sh index 8a16d3243..6e65ff0f8 100755 --- a/.ci/compile.sh +++ b/.ci/compile.sh @@ -1,33 +1,127 @@ -#!/bin/bash +#!/usr/bin/env bash -# This script is to be used by the ci environment from the project root directory, do not use it from somewhere else. +# Compiles Cockatrice inside GitHub Actions CI, run only from project root directory (GITHUB_WORKSPACE) +# +# Build flow and script structure: +# - Read options +# - Pre-checks (CI, Servatrice schema) +# - Prepare compilation (CMake options, OS-specific configuration) +# - Pre-buld (ccache) +# - Build (Configure, Compile) +# - Post-build (ccache, Inspect, Test, Install, Package) +# +# Supported command-line options: +# --ccache [] Use ccache (USE_CCACHE) (optionally: provide cache size, e.g. "500M" or "1G" (CCACHE_SIZE)) +# --cmake-generator Sets the CMake generator (CMAKE_GENERATOR), e.g. "Ninja", "Visual Studio 18 2026" +# --debug Sets the build type (BUILDTYPE --> CMAKE_BUILD_TYPE) +# --dir Sets the name of the build dir (BUILD_DIR) +# --evict-ccache Evicts compiler cache older than after build (CCACHE_EVICTION_AGE), e.g. "7d" +# --install Runs cmake install (MAKE_INSTALL) +# --no-client Compiles without Cockatrice and Oracle (MAKE_NO_CLIENT) +# --package [] Runs cmake package (MAKE_PACKAGE) (optionally: define type (PACKAGE_TYPE)), e.g. "DEB" [Linux only?] +# --release Sets the build type (BUILDTYPE --> CMAKE_BUILD_TYPE) +# --server Compiles Servatrice (MAKE_SERVER) +# --suffix Renames package with provided suffix (PACKAGE_SUFFIX), e.g. "-macOS15" +# --target-macos-version Sets the min OS version (TARGET_MACOS_VERSION), e.g. "14" [macOS only] +# --test Runs tests (MAKE_TEST) +# --vcpkg Use vcpkg package manager to resolve dependencies (USE_VCPKG) +# +# Exit codes: +# 1 --> Failure +# 3 --> Invalid argument(s) -# Compiles cockatrice inside of a ci environment -# --install runs make install -# --package [] runs make package, optionally force the type -# --suffix renames package with this suffix, requires arg -# --server compiles servatrice -# --test runs tests -# --debug or --release sets the build type ie CMAKE_BUILD_TYPE -# --ccache [] uses ccache and shows stats, optionally provide size -# --evict-ccache runs ccache eviction based on given age after build -# --dir sets the name of the build dir, default is "build" -# --cmake-generator sets CMAKE_GENERATOR as used by cmake -# --target-macos-version sets the min os version - only used for macOS builds -# uses env: BUILDTYPE MAKE_INSTALL MAKE_PACKAGE PACKAGE_TYPE PACKAGE_SUFFIX MAKE_SERVER MAKE_NO_CLIENT MAKE_TEST USE_CCACHE CCACHE_SIZE CCACHE_EVICTION_AGE BUILD_DIR CMAKE_GENERATOR TARGET_MACOS_VERSION -# (correspond to args: --debug/--release --install --package --suffix --server --test --ccache --dir ) -# exitcode: 1 for failure, 3 for invalid arguments +set -euo pipefail -# Read arguments + +### Initialize configuration variables: +# Precedence: command-line options > environment variables > built-in script defaults +BUILDTYPE="${BUILDTYPE:-Release}" # See "--debug" and "--release" flags (defaults to "Release" if omitted) +BUILD_DIR="${BUILD_DIR:-build}" # See value for "--dir" option (defaults to "build" if omitted) +CCACHE_EVICTION_AGE="${CCACHE_EVICTION_AGE:-}" # See value for "--evict-ccache" option +CCACHE_SIZE="${CCACHE_SIZE:-}" # See value for "--ccache" option +CMAKE_GENERATOR="${CMAKE_GENERATOR:-}" # See "--cmake-generator" option +MAKE_INSTALL="${MAKE_INSTALL:-0}" # See "--install" flag +MAKE_NO_CLIENT="${MAKE_NO_CLIENT:-0}" # See "--no-client" flag +MAKE_PACKAGE="${MAKE_PACKAGE:-0}" # See "--package" option +MAKE_SERVER="${MAKE_SERVER:-0}" # See "--server" flag +MAKE_TEST="${MAKE_TEST:-0}" # See "--test" flag +PACKAGE_SUFFIX="${PACKAGE_SUFFIX:-}" # See "--suffix" option +PACKAGE_TYPE="${PACKAGE_TYPE:-}" # See value for "--package" option +TARGET_MACOS_VERSION="${TARGET_MACOS_VERSION:-}" # See "--target-macos-version" option +USE_CCACHE="${USE_CCACHE:-0}" # See "--ccache" option +USE_VCPKG="${USE_VCPKG:-0}" # See "--vcpkg" flag + + +### Read options while [[ $# != 0 ]]; do case "$1" in - '--') + + # Flags (no argument) + '--debug') + BUILDTYPE="Debug" shift ;; '--install') MAKE_INSTALL=1 shift ;; + '--no-client') + MAKE_NO_CLIENT=1 + shift + ;; + '--release') + BUILDTYPE="Release" + shift + ;; + '--server') + MAKE_SERVER=1 + shift + ;; + '--test') + MAKE_TEST=1 + shift + ;; + '--vcpkg') + USE_VCPKG=1 + shift + ;; + + # Options (accept an argument) + '--ccache') + USE_CCACHE=1 + shift + if [[ $# != 0 && ${1:0:1} != - ]]; then + CCACHE_SIZE="$1" + shift + fi + ;; + '--cmake-generator') + shift + if [[ $# == 0 ]]; then + echo "::error file=$0::--cmake-generator expects an argument" + exit 3 + fi + CMAKE_GENERATOR="$1" + shift + ;; + '--dir') + shift + if [[ $# == 0 ]]; then + echo "::error file=$0::--dir expects an argument" + exit 3 + fi + BUILD_DIR="$1" + shift + ;; + '--evict-ccache') + shift + if [[ $# == 0 ]]; then + echo "::error file=$0::--evict-ccache expects an argument" + exit 3 + fi + CCACHE_EVICTION_AGE="$1" + shift + ;; '--package') MAKE_PACKAGE=1 shift @@ -45,65 +139,6 @@ while [[ $# != 0 ]]; do PACKAGE_SUFFIX="$1" shift ;; - '--server') - MAKE_SERVER=1 - shift - ;; - '--no-client') - MAKE_NO_CLIENT=1 - shift - ;; - '--test') - MAKE_TEST=1 - shift - ;; - '--debug') - BUILDTYPE="Debug" - shift - ;; - '--release') - BUILDTYPE="Release" - shift - ;; - '--ccache') - USE_CCACHE=1 - shift - if [[ $# != 0 && ${1:0:1} != - ]]; then - CCACHE_SIZE="$1" - shift - fi - ;; - '--evict-ccache') - shift - if [[ $# == 0 ]]; then - echo "::error file=$0::--evict-ccache expects an argument" - exit 3 - fi - CCACHE_EVICTION_AGE=$1 - shift - ;; - '--vcpkg') - USE_VCPKG=1 - shift - ;; - '--dir') - shift - if [[ $# == 0 ]]; then - echo "::error file=$0::--dir expects an argument" - exit 3 - fi - BUILD_DIR="$1" - shift - ;; - '--cmake-generator') - shift - if [[ $# == 0 ]]; then - echo "::error file=$0::--cmake-generator expects an argument" - exit 3 - fi - export CMAKE_GENERATOR=$1 - shift - ;; '--target-macos-version') shift if [[ $# == 0 ]]; then @@ -113,70 +148,82 @@ while [[ $# != 0 ]]; do TARGET_MACOS_VERSION="$1" shift ;; + + # Positional arguments are not supported + '--') + shift + if [[ $# != 0 ]]; then + echo "::error file=$0::Unexpected positional arguments: $*" + exit 3 + fi + break + ;; + + # Unknown options *) - echo "::error file=$0::unrecognized option: $1" + echo "::error file=$0::Unrecognized option: $1" exit 3 ;; esac done -set -e -# Setup -./servatrice/check_schema_version.sh -if [[ ! $BUILDTYPE ]]; then - BUILDTYPE=Release +### Pre-checks + +# CI context (GitHub Actions provided environment variable) +if [[ -z ${RUNNER_OS:-} ]]; then + echo "::notice::RUNNER_OS (GitHub Actions CI environment variable) is not available and OS-specific build configuration will be skipped" fi -if [[ ! $BUILD_DIR ]]; then - BUILD_DIR="build" + +# Schema version consistency +if [[ $MAKE_SERVER == 1 ]]; then + ./servatrice/check_schema_version.sh fi -mkdir -p "$BUILD_DIR" -cd "$BUILD_DIR" -# Set minimum CMake Version -export CMAKE_POLICY_VERSION_MINIMUM=3.10 -# Add cmake flags +### Prepare compilation + +# CMake options flags=("-DCMAKE_BUILD_TYPE=$BUILDTYPE") -if [[ $MAKE_SERVER ]]; then - flags+=("-DWITH_SERVER=1") + +if [[ -n $CMAKE_GENERATOR ]]; then + flags+=(-G "$CMAKE_GENERATOR") fi -if [[ $MAKE_NO_CLIENT ]]; then +if [[ $MAKE_NO_CLIENT == 1 ]]; then flags+=("-DWITH_CLIENT=0" "-DWITH_ORACLE=0") fi -if [[ $MAKE_TEST ]]; then +if [[ $MAKE_SERVER == 1 ]]; then + flags+=("-DWITH_SERVER=1") +fi +if [[ $MAKE_TEST == 1 ]]; then flags+=("-DTEST=1") fi -if [[ $USE_CCACHE ]]; then +if [[ -n $PACKAGE_TYPE ]]; then + flags+=("-DCPACK_GENERATOR=$PACKAGE_TYPE") +fi +if [[ $USE_CCACHE == 1 ]]; then flags+=("-DUSE_CCACHE=1") - if [[ $CCACHE_SIZE ]]; then - # note, this setting persists after running the script + if [[ -n $CCACHE_SIZE ]]; then + # Note: Setting persists after running the script ccache --max-size "$CCACHE_SIZE" fi fi -if [[ $PACKAGE_TYPE ]]; then - flags+=("-DCPACK_GENERATOR=$PACKAGE_TYPE") -fi -if [[ $USE_VCPKG ]]; then +if [[ $USE_VCPKG == 1 ]]; then flags+=("-DUSE_VCPKG=1") flags+=("-DVCPKG_INSTALL_OPTIONS=--x-abi-tools-use-exact-versions") fi -# Add cmake --build flags +# CMake --build options buildflags=(--config "$BUILDTYPE") -function ccachestatsverbose() { - # note, verbose only works on newer ccache, discard the error - local got - if got="$(ccache --show-stats --verbose 2>/dev/null)"; then - echo "$got" - else - ccache --show-stats - fi -} +if [[ ${RUNNER_OS:-} == "Windows" ]]; then + # Enable MSBuild switches for MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/ + # and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt + buildflags+=(-- -p:UseMultiToolTask=true -p:EnableClServerMode=true) +fi -# Compile -if [[ $RUNNER_OS == macOS ]]; then +# Other OS-specific configuration (GitHub Actions runner) +if [[ ${RUNNER_OS:-} == "macOS" ]]; then # QTDIR is needed for macOS since we actually only use the cached thin Qt binaries instead of the install-qt-action, # which sets a few environment variables if QTDIR=$(find "$GITHUB_WORKSPACE/Qt" -depth -maxdepth 2 -name macos -type d -print -quit); then @@ -185,42 +232,52 @@ if [[ $RUNNER_OS == macOS ]]; then echo "could not find QTDIR!" exit 2 fi - # the qtdir is located at Qt/[qtversion]/macos - # we use find to get the first subfolder with the name "macos" - # this works independent of the qt version as there should be only one version installed on the runner at a time + + # The qtdir is located at Qt//macos + # We use "find" to get the first subfolder with the name "macos" + # This works independent of the Qt version as there should be only one version installed on the runner at a time export QTDIR - if [[ $TARGET_MACOS_VERSION ]]; then - # CMAKE_OSX_DEPLOYMENT_TARGET is a vanilla cmake flag needed to compile to target macOS version + if [[ -n $TARGET_MACOS_VERSION ]]; then + # CMAKE_OSX_DEPLOYMENT_TARGET is a vanilla CMake option needed to compile to target macOS version flags+=("-DCMAKE_OSX_DEPLOYMENT_TARGET=$TARGET_MACOS_VERSION") - # vcpkg dependencies need a vcpkg triplet file to compile to the target macOS version - # an easy way is to copy the x64-osx.cmake file and modify it - triplets_dir="/tmp/cmake/triplets" - triplet_version="custom-triplet" - triplet_file="$triplets_dir/$triplet_version.cmake" - arch=$(uname -m) - if [[ $arch == x86_64 ]]; then - arch="x64" + if [[ $USE_VCPKG == 1 ]]; then + echo "vcpkg triplet" + # vcpkg dependencies need a vcpkg triplet file to compile to the target macOS version + # An easy way is to copy the x64-osx.cmake file and modify it + triplets_dir="/tmp/cmake/triplets" + triplet_version="custom-triplet" + triplet_file="$triplets_dir/$triplet_version.cmake" + arch=$(uname -m) + + if [[ $arch == x86_64 ]]; then + arch="x64" + fi + + mkdir -p "$triplets_dir" + triplet_source="./vcpkg/triplets/$arch-osx.cmake" + + if [[ ! -f "$triplet_source" ]]; then + triplet_source="./vcpkg/triplets/community/$arch-osx.cmake" + fi + + cp "$triplet_source" "$triplet_file" + echo "set(VCPKG_CMAKE_SYSTEM_VERSION $TARGET_MACOS_VERSION)" >>"$triplet_file" + echo "set(VCPKG_OSX_DEPLOYMENT_TARGET $TARGET_MACOS_VERSION)" >>"$triplet_file" + flags+=("-DVCPKG_OVERLAY_TRIPLETS=$triplets_dir") + flags+=("-DVCPKG_HOST_TRIPLET=$triplet_version") + flags+=("-DVCPKG_TARGET_TRIPLET=$triplet_version") + echo "::endgroup::" + + echo "::group::Generated triplet $triplet_file" + cat "$triplet_file" + echo "::endgroup::" fi - mkdir -p "$triplets_dir" - triplet_source="../vcpkg/triplets/$arch-osx.cmake" - if [[ ! -f "$triplet_source" ]]; then - triplet_source="../vcpkg/triplets/community/$arch-osx.cmake" - fi - cp "$triplet_source" "$triplet_file" - echo "set(VCPKG_CMAKE_SYSTEM_VERSION $TARGET_MACOS_VERSION)" >>"$triplet_file" - echo "set(VCPKG_OSX_DEPLOYMENT_TARGET $TARGET_MACOS_VERSION)" >>"$triplet_file" - flags+=("-DVCPKG_OVERLAY_TRIPLETS=$triplets_dir") - flags+=("-DVCPKG_HOST_TRIPLET=$triplet_version") - flags+=("-DVCPKG_TARGET_TRIPLET=$triplet_version") - echo "::group::Generated triplet $triplet_file" - cat "$triplet_file" - echo "::endgroup::" fi - echo "::group::Signing Certificate" - if [[ -n "$MACOS_CERTIFICATE_NAME" ]]; then + echo "::group::Setup signing certificate" + if [[ -n $MACOS_CERTIFICATE_NAME ]]; then echo "$MACOS_CERTIFICATE" | base64 --decode >"certificate.p12" security create-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain security default-keychain -s build.keychain @@ -234,9 +291,9 @@ if [[ $RUNNER_OS == macOS ]]; then fi echo "::endgroup::" - if [[ $MAKE_PACKAGE ]]; then + if [[ $MAKE_PACKAGE == 1 ]]; then # Workaround https://github.com/actions/runner-images/issues/7522 - # have hdiutil repeat the command 10 times in hope of success + # Have hdiutil repeat the command 10 times in hope of success hdiutil_script="/tmp/hdiutil.sh" # shellcheck disable=SC2016 echo '#!/bin/bash @@ -252,44 +309,78 @@ if [[ $RUNNER_OS == macOS ]]; then flags+=(-DCPACK_COMMAND_HDIUTIL="$hdiutil_script") fi -elif [[ $RUNNER_OS == Windows ]]; then - # Enable MTT, see https://devblogs.microsoft.com/cppblog/improved-parallelism-in-msbuild/ - # and https://devblogs.microsoft.com/cppblog/cpp-build-throughput-investigation-and-tune-up/#multitooltask-mtt - buildflags+=(-- -p:UseMultiToolTask=true -p:EnableClServerMode=true) +elif [[ ${RUNNER_OS:-} == "Windows" ]]; then + : + +elif [[ ${RUNNER_OS:-} == "Linux" ]]; then + : + fi -if [[ $USE_CCACHE ]]; then - echo "::group::Show ccache stats" - ccachestatsverbose + +### Pre-build + +# ccache +if [[ $USE_CCACHE == 1 ]]; then + echo "::group::Show ccache configuration" + ccache --version + ccache --show-config + echo " -----" + ccache --show-stats + ccache --show-compression + echo " -----" + ccache --show-stats --verbose + ccache --show-compression + echo " -----" + ccache --zero-stats + echo " -----" + ccache --show-stats + echo " -----" + ccache --show-stats --verbose echo "::endgroup::" fi -echo "::group::Configure cmake" + +### Build + +# Configure CMake +echo "::group::Generate buildsystem" cmake --version -echo "Running cmake with flags: ${flags[*]}" -cmake .. "${flags[@]}" +echo "Running CMake configuration with following flags: ${flags[*]}" +cmake -S . -B "$BUILD_DIR" "${flags[@]}" echo "::endgroup::" +# Compile echo "::group::Build project" -echo "Running cmake --build with flags: ${buildflags[*]}" -cmake --build . "${buildflags[@]}" +echo "Running CMake with following build flags: ${buildflags[*]}" +cmake --build "$BUILD_DIR" "${buildflags[@]}" echo "::endgroup::" -if [[ $USE_CCACHE ]]; then - if [[ $CCACHE_EVICTION_AGE ]]; then + +### Post-build + +# ccache +if [[ $USE_CCACHE == 1 ]]; then + + if [[ -n $CCACHE_EVICTION_AGE ]]; then echo "::group::evict ccache files older than $CCACHE_EVICTION_AGE" ccache --evict-older-than "$CCACHE_EVICTION_AGE" echo "::endgroup::" fi - echo "::group::Show ccache stats again" - ccachestatsverbose + + echo "::group::Show ccache statistics" + ccache --show-stats --verbose + ccache --show-compression echo "::endgroup::" -elif [[ $CCACHE_EVICTION_AGE ]]; then + +elif [[ -n $CCACHE_EVICTION_AGE ]]; then echo "::error file=$0::ccache eviction is enabled while ccache is disabled!" fi -if [[ $RUNNER_OS == macOS ]]; then +# Inspect +if [[ ${RUNNER_OS:-} == "macOS" ]]; then echo "::group::Inspect Mach-O binaries" + for app in cockatrice oracle servatrice; do binary="$GITHUB_WORKSPACE/build/$app/$app.app/Contents/MacOS/$app" echo "Inspecting $app..." @@ -298,30 +389,49 @@ if [[ $RUNNER_OS == macOS ]]; then lipo -info "$binary" echo "" done + echo "::endgroup::" fi -if [[ $MAKE_TEST ]]; then +# Test +if [[ $MAKE_TEST == 1 ]]; then echo "::group::Run tests" - ctest -C "$BUILDTYPE" --output-on-failure + ctest --version + ctest --build-config "$BUILDTYPE" --test-dir "$BUILD_DIR" --output-on-failure echo "::endgroup::" fi -if [[ $MAKE_INSTALL ]]; then +# Install +if [[ $MAKE_INSTALL == 1 ]]; then echo "::group::Install" - cmake --build . --target install --config "$BUILDTYPE" + cmake --install "$BUILD_DIR" --config "$BUILDTYPE" echo "::endgroup::" fi -if [[ $MAKE_PACKAGE ]]; then +# Package +if [[ $MAKE_PACKAGE == 1 ]]; then + echo "::group::Debug NSIS / CPack" + cat "_CPack_Packages/win64/NSIS/NSISOutput.log" + echo " -----" + find . -name "NSIS.definitions.nsh" + find "$BUILD_DIR" -name "NSIS.definitions.nsh" + ls -l "$BUILD_DIR/NSIS.definitions.nsh" + echo "::endgroup:" + echo "::group::Create package" - cmake --build . --target package --config "$BUILDTYPE" + cpack --version + ( + cd "$BUILD_DIR" + cpack + ) + # cpack --config "$BUILD_DIR/CPackConfig.cmake" + # cmake --build "$BUILD_DIR" --target package + #TODO included --config? compare with former isntall and other --target variants used echo "::endgroup::" - if [[ $PACKAGE_SUFFIX ]]; then + if [[ -n $PACKAGE_SUFFIX ]]; then echo "::group::Update package name" - cd .. - BUILD_DIR="$BUILD_DIR" .ci/name_build.sh "$PACKAGE_SUFFIX" + .ci/name_build.sh "$PACKAGE_SUFFIX" echo "::endgroup::" fi fi diff --git a/.ci/lint_cpp.sh b/.ci/lint_cpp.sh index 9786a83fc..b934c0307 100755 --- a/.ci/lint_cpp.sh +++ b/.ci/lint_cpp.sh @@ -1,9 +1,9 @@ #!/bin/bash -# fetch master branch +# Fetch master branch git fetch origin master -# unshallow if needed +# Unshallow if needed echo "Finding merge base" if ! git merge-base origin/master HEAD; then echo "Could not find merge base, unshallowing repo" @@ -32,7 +32,6 @@ case $err in *** *** *********************************************************** -Exiting... EOM exit 2 ;; @@ -48,7 +47,6 @@ EOM *** *** *********************************************************** -Exiting... EOM exit 0 ;; diff --git a/.ci/name_build.sh b/.ci/name_build.sh index 85818bbd9..d221534f1 100755 --- a/.ci/name_build.sh +++ b/.ci/name_build.sh @@ -1,49 +1,55 @@ -#!/bin/bash -# used by the ci to rename build artifacts -# renames the file to [original name][SUFFIX].[original extension] -# where SUFFIX is either available in the environment or as the first arg -# expected to be run in the build directory unless BUILD_DIR is set -# adds output to GITHUB_OUTPUT -builddir="${BUILD_DIR:=.}" -findrx="Cockatrice-*.*" +#!/usr/bin/env bash -if [[ $1 ]]; then - SUFFIX="$1" -fi +# Used by the CI build script to rename package artifacts +# +# Appends PACKAGE_SUFFIX to the package's filename +# = +# = +# PACKAGE_SUFFIX must be passed as the first argument to the script +# Adds output to GITHUB_OUTPUT +# +# Expected to be run in the repository root where CPack executes from and places its output binary +# Expects to be e.g. ".dmg", ".deb" or ".exe" (".tar.gz" etc. with more than one dot will break) +# If multiple packages match , the first match is used -# check env -if [[ ! $SUFFIX ]]; then - echo "::error file=$0::SUFFIX is missing" +set -euo pipefail + +# Initialize PACKAGE_SUFFIX from positional argument +PACKAGE_SUFFIX="${1:-}" + +# Check variable +if [[ -z $PACKAGE_SUFFIX ]]; then + echo "::error file=$0::Missing required argument: PACKAGE_SUFFIX" exit 2 fi -set -e +package_pattern="Cockatrice-*.*" -# find file -found="$(find "$builddir" -maxdepth 1 -type f -name "$findrx" -print -quit)" -path="${found%/*}" # remove all including first "/" from right side -file="${found##*/}" # remove all including last "/" from left side -if [[ ! $file ]]; then - echo "::error file=$0::could not find package" - exit 1 -fi -oldpwd="$PWD" -if ! cd "$path"; then - echo "::error file=$0::could not get file path" +# Find package in current directory +package_path="$(find "$PWD" -maxdepth 1 -type f -name "$package_pattern" -print -quit)" + +if [[ -z "$package_path" ]]; then + echo "::error file=$0::Could not find package" exit 1 fi -# set filename -name="${file%.*}" # remove all including first "." from right side -new_name="$name$SUFFIX" -extension="${file##*.}" # remove all including last "." from left side -filename="$new_name.$extension" -echo "renaming '$file' to '$filename'" -mv "$file" "$filename" +# = +package="${package_path##*/}" # e.g. "Cockatrice-3.0.0.deb" +filename="${package%.*}" # e.g. "Cockatrice-3.0.0" +extension=".${package##*.}" # e.g. ".deb" -cd "$oldpwd" -relative_path="$path/$filename" -ls -l "$relative_path" -echo "path=$relative_path" >>"$GITHUB_OUTPUT" -echo "name=$new_name" >>"$GITHUB_OUTPUT" -echo "fullname=$filename" >>"$GITHUB_OUTPUT" +# Rename package (build artifact) +filename_new="$filename$PACKAGE_SUFFIX" +package_new="$filename_new$extension" +package_path_new="$PWD/$package_new" + +echo "Renaming '$package' to '$package_new'" +mv "$package_path" "$package_path_new" +du -h "$package_path_new" + +#TODO remove package_path as it's default working direcotry / repo root? +{ + echo "package_path=$package_path_new" >> "$GITHUB_OUTPUT" + echo "package=$package_new" >> "$GITHUB_OUTPUT" + echo "filename=$filename_new" >> "$GITHUB_OUTPUT" +} >> "$GITHUB_OUTPUT" diff --git a/.github/workflows/desktop-build.yml b/.github/workflows/desktop-build.yml index f1846ecf6..f04bd8ed1 100644 --- a/.github/workflows/desktop-build.yml +++ b/.github/workflows/desktop-build.yml @@ -227,18 +227,18 @@ jobs: with: archive: false if-no-files-found: error - path: ${{ steps.build.outputs.path }} + path: ${{ steps.build.outputs.package }} # package is resolved against github.workspace - name: "Upload to release" id: upload_release if: matrix.package != 'skip' && needs.configure.outputs.tag != null shell: bash env: - asset_name: ${{ steps.build.outputs.fullname }} - asset_path: ${{ steps.build.outputs.path }} + package: ${{ steps.build.outputs.package }} + package_path: ${{ steps.build.outputs.package_path }} # <-- to check GH_TOKEN: ${{ github.token }} tag_name: ${{ needs.configure.outputs.tag }} - run: gh release upload "$tag_name" "$asset_path#$asset_name" + run: gh release upload "$tag_name" "$package_path#$package" # <-- to check - name: "Attest binary provenance" id: attestation @@ -246,15 +246,15 @@ jobs: uses: actions/attest@v4 with: show-summary: false - subject-path: ${{ steps.build.outputs.path }} + subject-path: ${{ steps.build.outputs.package_path }} # <-- to check - name: "Verify binary attestation" if: steps.attestation.outcome == 'success' shell: bash env: - BUILD_PATH: ${{ steps.build.outputs.path }} + PACKAGE_PATH: ${{ steps.build.outputs.package_path }} # <-- to check GH_TOKEN: ${{ github.token }} - run: gh attestation verify "$BUILD_PATH" --repo Cockatrice/Cockatrice + run: gh attestation verify "$PACKAGE_PATH" --repo Cockatrice/Cockatrice build-vcpkg: strategy: @@ -422,7 +422,7 @@ jobs: - name: "[Windows] Install NSIS" if: matrix.os == 'Windows' shell: bash - run: choco install nsis + run: choco install nsis --no-progress - name: "Setup vcpkg cache" id: vcpkg-cache @@ -451,6 +451,11 @@ jobs: VCPKG_BINARY_SOURCES: 'clear;files,${{ steps.vcpkg-cache.outputs.path }},readwrite' VCPKG_DISABLE_METRICS: 1 run: .ci/compile.sh --server --test --vcpkg + continue-on-error: true + + - name: "[Windows] DEBUG: Print NSIS log output" + if: matrix.os == 'Windows' + run: cat "_CPack_Packages/win64/NSIS/NSISOutput.log" # Delete used cache to emulate a ccache update. See https://github.com/actions/cache/issues/342 - name: "[macOS] Delete remote compiler cache (ccache)" @@ -475,20 +480,20 @@ jobs: if: matrix.os == 'macOS' && matrix.make_package && needs.configure.outputs.tag != null id: sign_macos env: - BUILD_PATH: ${{ steps.build.outputs.path }} + PACKAGE_PATH: ${{ steps.build.outputs.package_path }} MACOS_CERTIFICATE_NAME: ${{ secrets.PROD_MACOS_CERTIFICATE_NAME }} MACOS_CI_KEYCHAIN_PWD: ${{ secrets.PROD_MACOS_CI_KEYCHAIN_PWD }} run: | if [[ -n "$MACOS_CERTIFICATE_NAME" ]] then security unlock-keychain -p "$MACOS_CI_KEYCHAIN_PWD" build.keychain - /usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose "$BUILD_PATH" + /usr/bin/codesign --sign="$MACOS_CERTIFICATE_NAME" --entitlements=".ci/macos.entitlements" --options=runtime --force --deep --timestamp --verbose "$PACKAGE_PATH" fi - name: "[macOS] Notarize app bundle" if: matrix.os == 'macOS' && steps.sign_macos.outcome == 'success' env: - BUILD_PATH: ${{ steps.build.outputs.path }} + PACKAGE_PATH: ${{ steps.build.outputs.package_path }} MACOS_NOTARIZATION_APPLE_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_APPLE_ID }} MACOS_NOTARIZATION_PWD: ${{ secrets.PROD_MACOS_NOTARIZATION_PWD }} MACOS_NOTARIZATION_TEAM_ID: ${{ secrets.PROD_MACOS_NOTARIZATION_TEAM_ID }} @@ -503,7 +508,7 @@ jobs: # Therefore, we create a zip file containing our app bundle, so that we can send it to the # notarization service echo "Creating temp notarization archive" - ditto -c -k --keepParent "$BUILD_PATH" "notarization.zip" + ditto -c -k --keepParent "$PACKAGE_PATH" "notarization.zip" # Here we send the notarization request to the Apple's Notarization service, waiting for the result. # This typically takes a few seconds inside a CI environment, but it might take more depending on the App @@ -515,7 +520,7 @@ jobs: # Finally, we need to "attach the staple" to our executable, which will allow our app to be # validated by macOS even when an internet connection is not available. echo "Attach staple" - xcrun stapler staple "$BUILD_PATH" + xcrun stapler staple "$PACKAGE_PATH" fi - name: "Upload artifact" @@ -525,14 +530,14 @@ jobs: with: archive: false if-no-files-found: error - path: ${{ steps.build.outputs.path }} + path: ${{ steps.build.outputs.package_path }} - name: "[Windows] Upload PDBs (Program Databases)" if: matrix.os == 'Windows' && github.ref_type != 'tag' uses: actions/upload-artifact@v7 with: if-no-files-found: error - name: ${{ steps.build.outputs.name }}-PDBs + name: ${{ steps.build.outputs.filename }}-PDBs path: | build/cockatrice/Release/*.pdb build/oracle/Release/*.pdb @@ -543,11 +548,11 @@ jobs: id: upload_release shell: bash env: - asset_name: ${{ steps.build.outputs.fullname }} - asset_path: ${{ steps.build.outputs.path }} + package: ${{ steps.build.outputs.package }} + package_path: ${{ steps.build.outputs.package_path }} GH_TOKEN: ${{ github.token }} tag_name: ${{ needs.configure.outputs.tag }} - run: gh release upload "$tag_name" "$asset_path#$asset_name" + run: gh release upload "$tag_name" "$package_path#$package" - name: "Attest binary provenance" if: steps.upload_release.outcome == 'success' @@ -555,12 +560,12 @@ jobs: uses: actions/attest@v4 with: show-summary: false - subject-path: ${{ steps.build.outputs.path }} + subject-path: ${{ steps.build.outputs.package_path }} - name: "Verify binary attestation" if: steps.attestation.outcome == 'success' shell: bash env: - BUILD_PATH: ${{ steps.build.outputs.path }} + PACKAGE_PATH: ${{ steps.build.outputs.package_path }} GH_TOKEN: ${{ github.token }} - run: gh attestation verify "$BUILD_PATH" --repo Cockatrice/Cockatrice + run: gh attestation verify "$PACKAGE_PATH" --repo Cockatrice/Cockatrice diff --git a/CMakeLists.txt b/CMakeLists.txt index c10e1db68..7a962e457 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,11 @@ # Cockatrice's main CMakeLists.txt # # This is basically a wrapper to enable/disable the compilation -# of the different projects: servatrice, cockatrice, test +# of the different projects: cockatrice, servatrice, test # This file sets all the variables shared between the projects # like the installation path, compilation flags etc.. -# cmake 3.16 is required if using qt6 +# CMake 3.16 is required if using Qt6 cmake_minimum_required(VERSION 3.10) # Early detect ccache @@ -27,20 +27,16 @@ option(USE_VCPKG "Use vcpkg regardless of OS" OFF) # Default to "Release" build type # User-provided value for CMAKE_BUILD_TYPE must be checked before the PROJECT() call -if(DEFINED CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE - ${CMAKE_BUILD_TYPE} - CACHE STRING "Type of build" - ) -else() +if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release - CACHE STRING "Type of build" + CACHE STRING "Build type" ) endif() if(USE_CCACHE) find_program(CCACHE_PROGRAM ccache) + if(CCACHE_PROGRAM) # Support Unix Makefiles and Ninja set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") @@ -54,6 +50,7 @@ if(WIN32 OR USE_VCPKG) ${CMAKE_CURRENT_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE STRING "Vcpkg toolchain file" ) + # Qt path set by user or env var if(QTDIR OR DEFINED ENV{QTDIR} @@ -76,22 +73,23 @@ endif() # Version can be overriden by git tags, see cmake/getversion.cmake project("Cockatrice" VERSION 3.1.0) -# Set release name if not provided via env/cmake var +# Set release name if not provided via ENV/CMake var if(NOT DEFINED GIT_TAG_RELEASENAME) set(GIT_TAG_RELEASENAME "Graduation Day") endif() -# Use c++20 for all targets +# Use C++20 for all targets set(CMAKE_CXX_STANDARD 20 CACHE STRING "C++ ISO Standard" ) set(CMAKE_CXX_STANDARD_REQUIRED True) +set(CMAKE_CXX_EXTENSIONS OFF) # Set conventional loops set(CMAKE_ALLOW_LOOSE_LOOP_CONSTRUCTS true) -# Search path for cmake modules +# Search path for CMake modules set(COCKATRICE_CMAKE_PATH "${PROJECT_SOURCE_DIR}/cmake") list(INSERT CMAKE_MODULE_PATH 0 "${COCKATRICE_CMAKE_PATH}") @@ -102,14 +100,14 @@ include(createversionfile) # Define a proper install path if(UNIX) - if(APPLE) - # macOS - # Due to the special bundle structure ignore - # the prefix eventually set by the user. + + if(APPLE) # macOS + # Due to the special bundle structure ignore the prefix eventually set by the user set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/release) # Force ccache usage if available get_property(RULE_LAUNCH_COMPILE GLOBAL PROPERTY RULE_LAUNCH_COMPILE) + if(RULE_LAUNCH_COMPILE) message(STATUS "Force enabling CCache usage under macOS") # Set up wrapper scripts @@ -123,39 +121,52 @@ if(UNIX) set(CMAKE_XCODE_ATTRIBUTE_LD "${CMAKE_BINARY_DIR}/launch-c") set(CMAKE_XCODE_ATTRIBUTE_LDPLUSPLUS "${CMAKE_BINARY_DIR}/launch-cxx") endif() - else() - # Linux / BSD + + else() # Linux / BSD if(CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) - #fix package build + + # Fix package build if(PREFIX) set(CMAKE_INSTALL_PREFIX ${PREFIX}) else() set(CMAKE_INSTALL_PREFIX /usr/local) endif() + endif() endif() -elseif(WIN32) + +elseif(WIN32) # Windows set(CMAKE_INSTALL_PREFIX ${CMAKE_BINARY_DIR}/rundir/${CMAKE_BUILD_TYPE}) endif() # Define proper compilation flags -if(MSVC) - # Disable Warning C4251, C++20 compatibility, Multi-threaded Builds, Warn Detection, Unwind Semantics, Debug Symbols - set(CMAKE_CXX_FLAGS "/wd4251 /Zc:__cplusplus /std:c++20 /permissive- /W4 /MP /EHsc /Zi") - # Visual Studio: Maximum Optimization, Multi-threaded DLL +if(MSVC) # Microsoft Visual C++ compiler + # /wd4251 Suppress C4251 (DLL interface) warnings + # /W4 Enable warning level 4 + # /MP Enable multi-threaded building + # /EHsc Enable standard C++ exception handling + # /Zi Generate debugging information (Program Databases, PDBs) + set(CMAKE_CXX_FLAGS "/wd4251 /W4 /MP /EHsc /Zi") + + # /Ox Enable maximum optimization + # /MD Link against the multi-threaded DLL runtime library (Release CRT) set(CMAKE_CXX_FLAGS_RELEASE "/Ox /MD") - # Visual Studio: No Optimization, Multi-threaded Debug DLL + + # /Od Disable optimization + # /MDd Link against the multi-threaded Debug DLL runtime library (Debug CRT) set(CMAKE_CXX_FLAGS_DEBUG "/Od /MDd") - # Generate PDB, even when in release (So developers can better analyze crash logs) + # Generate PDBs, even when in release (Allow developers to better analyze crash logs) set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /DEBUG /OPT:REF /OPT:ICF") add_compile_definitions(_SILENCE_STDEXT_ARR_ITERS_DEPRECATION_WARNING) + elseif(CMAKE_COMPILER_IS_GNUCXX) - # linux/gcc, bsd/gcc, windows/mingw + # Linux/GCC, BSD/GCC, Windows/MinGW include(CheckCXXCompilerFlag) set(CMAKE_CXX_FLAGS_RELEASE "-s -O2") + if(WARNING_AS_ERROR) set(CMAKE_CXX_FLAGS_DEBUG "-ggdb -O0 -Wall -Wextra -Werror") else() @@ -174,23 +185,26 @@ elseif(CMAKE_COMPILER_IS_GNUCXX) -Wno-error=delete-non-virtual-dtor -Wno-error=sign-compare -Wno-error=missing-declarations - -Wno-error=sfinae-incomplete # GCC 16+: Qt MOC + protobuf forward decls trigger this + -Wno-error=sfinae-incomplete # GCC 16+: Qt MOC + protobuf forward declarations trigger this ) foreach(FLAG ${ADDITIONAL_DEBUG_FLAGS}) check_cxx_compiler_flag("${FLAG}" CXX_HAS_WARNING_${FLAG}) + if(CXX_HAS_WARNING_${FLAG}) set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${FLAG}") endif() endforeach() -else() - # other: osx/llvm, bsd/llvm + +else() # Other: macOS/LLVM, BSD/LLVM set(CMAKE_CXX_FLAGS_RELEASE "-O2") + if(WARNING_AS_ERROR) set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra -Werror -Wno-unused-parameter") else() set(CMAKE_CXX_FLAGS_DEBUG "-g -O0 -Wall -Wextra") endif() + endif() # GNU systems need to define the Mersenne exponent for the RNG to compile w/o warning @@ -225,6 +239,7 @@ set(CMAKE_AUTOMOC TRUE) # Find other needed libraries find_package(Protobuf CONFIG) + if(NOT Protobuf_FOUND) find_package(Protobuf REQUIRED) endif() @@ -233,9 +248,11 @@ if(${Protobuf_VERSION} VERSION_LESS "3.21.0.0" AND NOT EXISTS "${Protobuf_PROTOC message(FATAL_ERROR "No protoc command found!") endif() -#Find OpenSSL +# Find OpenSSL if(WIN32) + find_package(OpenSSL REQUIRED) + if(OPENSSL_FOUND) include_directories(${OPENSSL_INCLUDE_DIRS}) else() @@ -246,7 +263,7 @@ if(WIN32) endif() endif() -#Find VCredist +# Find Visual C++ Redistributable if(MSVC) find_package(VCredistRuntime) endif() @@ -256,7 +273,9 @@ set(CPACK_PACKAGE_CONTACT "Zach Halpern ") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_NAME}") set(CPACK_PACKAGE_VENDOR "Cockatrice Development Team") set(CPACK_PACKAGE_DESCRIPTION - "Cockatrice is an open-source, multiplatform application for playing tabletop card games over a network. The program's server design prevents users from manipulating the game for unfair advantage. The client also provides a single-player mode, which allows users to brew while offline." + "Cockatrice is an open-source, multiplatform application for playing tabletop card games over a network. \ + The program's server design prevents users from manipulating the game for unfair advantage. \ + The client also provides a single-player mode, which allows users to brew while offline." ) set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE") set(CPACK_PACKAGE_VERSION_MAJOR "${PROJECT_VERSION_MAJOR}") @@ -265,7 +284,8 @@ set(CPACK_PACKAGE_VERSION_PATCH "${PROJECT_VERSION_PATCH}") set(CPACK_PACKAGE_FILE_NAME "${PROJECT_VERSION_FILENAME}") if(UNIX) - if(APPLE) + + if(APPLE) # macOS set(CPACK_GENERATOR DragNDrop ${CPACK_GENERATOR}) set(CPACK_GENERATOR "DragNDrop") set(CPACK_DMG_FORMAT "UDBZ") @@ -275,8 +295,8 @@ if(UNIX) set(CPACK_DMG_DS_STORE_SETUP_SCRIPT "${CMAKE_CURRENT_SOURCE_DIR}/cmake/CMakeDMGSetup.script") set(CPACK_DMG_BACKGROUND_IMAGE "${CMAKE_CURRENT_SOURCE_DIR}/cmake/dmgBackground.tif") set(CPACK_PRE_BUILD_SCRIPTS "${CMAKE_CURRENT_SOURCE_DIR}/cmake/SignMacApplications.cmake") - else() - # linux + + else() # Linux if(CPACK_GENERATOR STREQUAL "RPM") set(CPACK_RPM_PACKAGE_LICENSE "GPLv2") set(CPACK_RPM_MAIN_COMPONENT "cockatrice") @@ -287,7 +307,7 @@ if(UNIX) endif() set(CPACK_RPM_PACKAGE_GROUP "Amusements/Games") set(CPACK_RPM_PACKAGE_URL "http://github.com/Cockatrice/Cockatrice") - # stop directories from making package conflicts + # Stop directories from creating package conflicts set(CPACK_RPM_EXCLUDE_FROM_AUTO_FILELIST_ADDITION /usr/share/applications /usr/share/icons @@ -304,24 +324,25 @@ if(UNIX) set(CPACK_DEBIAN_PACKAGE_HOMEPAGE "http://github.com/Cockatrice/Cockatrice") if(Qt6_FOUND) set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt6multimedia6, libqt6svg6, qt6-qpa-plugins, qt6-image-formats-plugins") - set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libqt6sql6-mysql") # for connecting servatrice to a mysql db + set(CPACK_DEBIAN_PACKAGE_RECOMMENDS "libqt6sql6-mysql") # for connecting Servatrice to a MySQL DB elseif(Qt5_FOUND) set(CPACK_DEBIAN_PACKAGE_DEPENDS "libqt5multimedia5-plugins, libqt5svg5") endif() endif() endif() -elseif(WIN32) + +elseif(WIN32) # Windows set(CPACK_GENERATOR NSIS ${CPACK_GENERATOR}) - if("${CMAKE_GENERATOR_PLATFORM}" MATCHES "(x64)") + if(CMAKE_SIZEOF_VOID_P EQUAL 8) set(TRICE_IS_64_BIT 1) else() set(TRICE_IS_64_BIT 0) endif() - # Configure file with custom definitions for NSIS. + # Configure file with custom definitions for NSIS configure_file("${COCKATRICE_CMAKE_PATH}/NSIS.definitions.nsh.in" "${PROJECT_BINARY_DIR}/NSIS.definitions.nsh") - # include vcredist into the package; NSIS will take care of running it + # Include vcredist into the package, NSIS will take care of running it if(VCREDISTRUNTIME_FOUND) install(FILES "${VCREDISTRUNTIME_FILE}" DESTINATION ./) endif() @@ -368,6 +389,6 @@ if(TEST) endif() if(Qt6_FOUND AND Qt6_VERSION_MINOR GREATER_EQUAL 3) - # Qt6.3+ requires project finalization to support translations + # Qt 6.3+ requires project finalization to support translations qt6_finalize_project() endif() diff --git a/format.sh b/format.sh index 83dee9e28..b174bea2f 100755 --- a/format.sh +++ b/format.sh @@ -1,30 +1,30 @@ #!/bin/bash -# This script will run clang-format on all modified, non-3rd-party C++/Header files. +# This script will run Clang-Format on all modified, non-3rd-party C++/Header files. # Optionally runs cmake-format on all modified cmake files. -# Optionally runs shellcheck on all modified shell files. +# Optionally runs ShellCheck on all modified shell files. # Uses clang-format, cmake-format, git, diff, find and shellcheck # Never, ever, should this receive a path with a newline in it. Don't bother proofing it for that. set -o pipefail -# go to the project root directory, this file should be located in the project root directory +# Go to the project root directory, this file should be located in the project root directory olddir="$PWD" cd "${BASH_SOURCE%/*}/" || exit 2 # could not find path, this could happen with special links etc. -# defaults +# Defaults include=("cockatrice/src" \ -libcockatrice_* \ -"oracle/src" \ -"servatrice/src" \ -"tests") + libcockatrice_* \ + "oracle/src" \ + "servatrice/src" \ + "tests") exclude=("libcockatrice_rng/libcockatrice/rng/sfmt/" \ -"libcockatrice_utility/libcockatrice/utility/peglib.h" \ -"oracle/src/lzma/" \ -"oracle/src/qt-json/" \ -"oracle/src/zip/" \ -"servatrice/src/smtp/") -exts=("cpp" "h" "proto") + "libcockatrice_utility/libcockatrice/utility/peglib.h" \ + "oracle/src/lzma/" \ + "oracle/src/qt-json/" \ + "oracle/src/zip/" \ + "servatrice/src/smtp/") +extensions=("cpp" "h" "proto") cf_cmd="clang-format" branch="origin/master" cmakefile="CMakeLists.txt" @@ -33,9 +33,9 @@ cmakeinclude=("cmake/gtest-CMakeLists.txt.in") scripts="*.sh" color="--" verbosity=0 -sep="----------" +separator=" ----------" -# parse options +# Parse options while [[ $* ]]; do case "$1" in '-b'|'--branch') @@ -58,7 +58,7 @@ while [[ $* ]]; do ;; '-h'|'--help') cat <s are given, all source files in those directories of the project root @@ -165,7 +165,7 @@ EOM ;; *) if [[ ! $dashdash && $1 =~ ^-- ]]; then - echo "error in parsing arguments of $0: $1 is an unrecognized option" >&2 + echo "Error in parsing arguments of $0: $1 is an unrecognized option" >&2 exit 2 # input error fi if [[ ! $1 ]] || next_dir=$(cd "$olddir" && cd -- "$1" && pwd); then @@ -175,13 +175,13 @@ EOM fi if [[ $1 ]]; then if [[ $next_dir != $PWD/* ]]; then - echo "error in parsing arguments of $0: $next_dir is not in $PWD" >&2 + echo "Error in parsing arguments of $0: $next_dir is not in $PWD" >&2 exit 2 # input error fi include+=("$next_dir") fi else - echo "error in parsing arguments of $0: $1 is not a directory" >&2 + echo "Error in parsing arguments of $0: $1 is not a directory" >&2 exit 2 # input error fi if ! [[ $set_branch ]]; then @@ -192,39 +192,39 @@ EOM esac done -# check availability of clang-format +# Check availability of Clang-Format if ! hash $cf_cmd 2>/dev/null; then echo "could not find $cf_cmd" >&2 - # find any clang-format-x.x in /usr/bin + # Find any "clang-format-x.x" in /usr/bin cf_cmd=$(find /usr/bin -regex '.*/clang-format-[0-9]+\.[0-9]+' -print -quit) if [[ $cf_cmd ]]; then - echo "found $cf_cmd instead" >&2 + echo "Found $cf_cmd instead" >&2 else exit 3 # special exit code for missing dependency fi fi -# check availability of cmake-format +# Check availability of cmake-format if [[ $do_cmake ]] && ! hash cmake-format 2>/dev/null; then - echo "could not find cmake-format" >&2 + echo "Could not find cmake-format" >&2 exit 3 fi -# check availability of shellcheck +# Check availability of ShellCheck if [[ $do_shell ]] && ! hash shellcheck 2>/dev/null; then - echo "could not find shellcheck" >&2 + echo "Could not find shellcheck" >&2 exit 3 fi if [[ $branch ]]; then - # get all dirty files through git + # Get all dirty files through git if ! base=$(git merge-base "$branch" HEAD); then - echo "could not find git merge base" >&2 + echo "Could not find git merge base" >&2 exit 2 # input error fi mapfile -t basenames < <(git diff --diff-filter=d --name-only "$base") names=() - for ex in "${exts[@]}"; do + for ex in "${extensions[@]}"; do for path in "${include[@]}"; do for name in "${basenames[@]}"; do rx="^$path/.*\\.$ex$" @@ -260,7 +260,7 @@ if [[ $branch ]]; then fi else exts_o=() - for ext in "${exts[@]}"; do + for ext in "${extensions[@]}"; do exts_o+=(-o -name "*\\.$ext") done unset "exts_o[0]" # remove first -o @@ -274,7 +274,7 @@ else fi fi -# filter excludes +# Filter excludes for path in "${exclude[@]}"; do for i in "${!names[@]}"; do rx="^$path" @@ -284,12 +284,12 @@ for path in "${exclude[@]}"; do done done -# optionally print version +# Optionally print version if [[ $print_version ]]; then $cf_cmd -version [[ $do_cmake ]] && echo "cmake-format version $(cmake-format --version)" - [[ $do_shell ]] && echo "shellcheck $(shellcheck --version | grep "version:")" - echo "$sep" + [[ $do_shell ]] && echo "ShellCheck $(shellcheck --version | grep "version:")" + echo "$separator" fi if [[ ! ${cmake_names[*]} ]]; then @@ -302,7 +302,7 @@ if [[ ! ( ${names[*]} || $do_cmake || $do_shell ) ]]; then exit 0 # nothing to format means format is successful! fi -# format +# Format case $mode in diff) declare -i code=0 @@ -326,9 +326,10 @@ case $mode in fi done if (( code>0 )); then - echo "$sep" + echo "$separator" + echo "Affected file(s):" for name in "${files_to_format[@]}"; do - echo "$name" + echo " $name" done fi exit $code @@ -374,15 +375,15 @@ case $mode in cmake-format -i "${cmake_names[@]}" fi if [[ $do_shell ]]; then - echo "warning: --shell is not compatible with the current mode but shell files were modified!" >&2 - echo "recommendation: try $0 --diff --shell" >&2 + echo "Warning: --shell is not compatible with the current mode but shell files were modified!" >&2 + echo "Recommendation: try $0 --diff --shell" >&2 fi if (( verbosity>0 )); then count="${#names[*]}" if [[ $do_cmake ]]; then (( count+=${#cmake_names[*]} )) fi - echo "parsed $count files that differ from base $branch" + echo "Parsed $count files that differ from base $branch" fi ;; esac diff --git a/servatrice/check_schema_version.sh b/servatrice/check_schema_version.sh index c4aadf356..13c5f77f8 100755 --- a/servatrice/check_schema_version.sh +++ b/servatrice/check_schema_version.sh @@ -2,35 +2,41 @@ set -e +echo "::group::Check Servatrice database schema version" version_line="$(grep 'INSERT INTO cockatrice_schema_version' servatrice/servatrice.sql)" version_line="${version_line#*VALUES(}" declare -i schema_ver="${version_line%%)*}" -# shellcheck disable=2012 -latest_migration="$(ls -1 servatrice/migrations/ | tail -n1)" +latest_migration="$(printf '%s\n' servatrice/migrations/*.sql | sed 's#.*/##' | sort | tail -n1)" xtoysql="${latest_migration#servatrice_}" xtoy="${xtoysql%.sql}" -declare -i old_ver="10#${xtoy%_to_*}" #declare as integer with base 10, numbers with a leading 0 are normally interpreted as base 16 +declare -i old_ver="10#${xtoy%_to_*}" # declare as integer with base 10, numbers with a leading 0 are normally interpreted as base 16 declare -i new_ver="10#${xtoy#*_to_}" +echo "Schema version: $schema_ver" +echo "Latest migration: $latest_migration ($old_ver → $new_ver)" + if ((old_ver >= new_ver)); then - echo "New version $new_ver is not newer than $old_ver" - exit 1 + echo "New version $new_ver is not newer than $old_ver" + exit 1 fi if ((schema_ver != new_ver)); then - echo "Schema version $schema_ver does not equal new version $new_ver" - exit 1 + echo "Schema version $schema_ver does not match new version $new_ver" + exit 1 fi expected_sql="^UPDATE cockatrice_schema_version SET version=${new_ver} WHERE version=${old_ver};$" if ! grep -q "$expected_sql" "servatrice/migrations/$latest_migration"; then - echo "$latest_migration does not contain expected sql: $expected_sql" - exit 1 + echo "$latest_migration does not contain expected sql: $expected_sql" + exit 1 fi expected_define="^#define DATABASE_SCHEMA_VERSION $new_ver$" if ! grep -q "$expected_define" servatrice/src/servatrice_database_interface.h; then - echo "servatrice_database_interface.h does not contain expected #define: $expected_define" - exit 1 + echo "servatrice_database_interface.h does not contain expected #define: $expected_define" + exit 1 fi + +echo " ✓ Database schema version is consistent" +echo "::endgroup::" diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 857e0b041..ae6a7e98b 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -11,10 +11,9 @@ add_test(NAME server_card_counter_test COMMAND server_card_counter_test) add_test(NAME server_counter_test COMMAND server_counter_test) add_test(NAME deck_hash_performance_test COMMAND deck_hash_performance_test) +set_tests_properties(dummy_test PROPERTIES TIMEOUT 5) set_tests_properties(deck_hash_performance_test PROPERTIES TIMEOUT 5) -# Find GTest - add_executable(dummy_test dummy_test.cpp) add_executable(expression_test expression_test.cpp) add_executable(clamped_arithmetic_test clamped_arithmetic_test.cpp) @@ -24,6 +23,7 @@ add_executable(deck_hash_performance_test deck_hash_performance_test.cpp) add_executable(server_card_counter_test server_card_counter_test.cpp) add_executable(server_counter_test server_counter_test.cpp) +# Find GTest find_package(GTest) if(NOT GTEST_FOUND)