diff --git a/.github/workflows/core_build.yml b/.github/workflows/core_build.yml index 4a079dd2f..4a4d1ffcd 100644 --- a/.github/workflows/core_build.yml +++ b/.github/workflows/core_build.yml @@ -1,12 +1,21 @@ name: Linux Build on: push: - branches: [ master ] + paths-ignore: + - 'README.md' + - 'apps/**' + branches: [ master ] pull_request: - branches: [ master ] + paths-ignore: + - 'README.md' + - 'apps/**' + branches: [ master ] jobs: build: + strategy: + fail-fast: false + runs-on: ubuntu-latest steps: @@ -20,11 +29,27 @@ jobs: - name: Install Required Packages run: sudo apt-get install -y git make cmake clang libssl-dev libbz2-dev build-essential default-libmysqlclient-dev libace-dev libreadline-dev - - name: Update Compilers - run: source ./apps/ci/ci-compiler-update.sh + - name: Install OpenSSL 3.5.1 Package Manually + run: | + wget https://www.openssl.org/source/openssl-3.5.1.tar.gz + tar -xvf openssl-3.5.1.tar.gz + cd openssl-3.5.1 + ./config --prefix=/usr/local/openssl --openssldir=/usr/local/openssl + make -j$(nproc) + sudo make install + + - name: Set OpenSSL 3.5.1 Environment Variables + run: | + echo "OPENSSL_ROOT_DIR=/usr/local/openssl" >> $GITHUB_ENV + echo "OPENSSL_INCLUDE_DIR=/usr/local/openssl/include" >> $GITHUB_ENV + echo "OPENSSL_LIBRARIES=/usr/local/openssl/lib" >> $GITHUB_ENV + echo "/usr/local/openssl/lib" | sudo tee /etc/ld.so.conf.d/openssl-3.5.conf + sudo ldconfig - name: Check for Submodule Updates - run: source ./apps/ci/ci-submodule-update.sh + run: | + git submodule init + git submodule update - name: Build Mangos Project run: source ./apps/ci/ci-compile.sh diff --git a/.github/workflows/core_codestyle.yml b/.github/workflows/core_codestyle.yml index 3f9a73e0c..85bffb1b2 100644 --- a/.github/workflows/core_codestyle.yml +++ b/.github/workflows/core_codestyle.yml @@ -11,9 +11,10 @@ jobs: fail-fast: false runs-on: ubuntu-latest + name: Check Codestyling steps: - uses: actions/checkout@v2 - name: Check Codestyling - run: source ./apps/ci/ci-codestyle.sh + run: bash ./apps/ci/ci-codestyle.sh diff --git a/.github/workflows/core_windows_build.yml b/.github/workflows/core_windows_build.yml index 50af0d32e..40a70a2f6 100644 --- a/.github/workflows/core_windows_build.yml +++ b/.github/workflows/core_windows_build.yml @@ -1,9 +1,15 @@ name: Windows Build on: push: - branches: [ master ] + paths-ignore: + - 'README.md' + - 'apps/**' + branches: [ master ] pull_request: - branches: [ master ] + paths-ignore: + - 'README.md' + - 'apps/**' + branches: [ master ] jobs: build: diff --git a/.github/workflows/docker_build.yml b/.github/workflows/docker_build.yml index d505640c3..978668086 100644 --- a/.github/workflows/docker_build.yml +++ b/.github/workflows/docker_build.yml @@ -1,9 +1,15 @@ name: Docker Build on: push: - branches: [ master ] + paths-ignore: + - 'README.md' + - 'apps/**' + branches: [ master ] pull_request: - branches: [ master ] + paths-ignore: + - 'README.md' + - 'apps/**' + branches: [ master ] jobs: build: diff --git a/apps/ci/ci-codestyle.sh b/apps/ci/ci-codestyle.sh index ca9deab3a..aec6f280f 100644 --- a/apps/ci/ci-codestyle.sh +++ b/apps/ci/ci-codestyle.sh @@ -1,39 +1,195 @@ #!/bin/bash -set -e +# +# Advanced Code Styling Check for getMaNGOS +# Script written by Meltie2013 (https://github.com/Meltie2013) +# +# Copyright: 2025 +# Website: https://getmangos.eu/ +# +# Script Type: Bash +# +# Co-authors Area: +# +# Note from the author: Anyone is free to use this script but is asked to keep the original author name and GitHub url in the header. +# You can add co-authors to the header when the script is updated or changed for your project needs. Removing the original author +# from the header, will result in a DMCA (take-down). +# +# This script is viewed under the GPL-2.0 license and shall not be changed unless authorized by the original author. +# + +LOG_IGNORED_RULES=false # Set to true to print exception rule matches -echo "Starting Codestyling Script:" echo +echo "Checking For MaNGOS Coding Standards:" +echo "Starting Codestyling Script:" declare -A singleLineRegexChecks=( - ["[[:blank:]]$"]="Remove whitespace at the end of the lines above" - ["\t"]="Replace tabs with 4 spaces in the lines above" + # General whitespace/style rules + ["[[:blank:]]$"]="Remove whitespace at the end of the lines" + ["\t"]="Replace tabs with 4 spaces in the lines" + + # Exception patterns (ignored, but still shown in summary) + ["^[[:blank:]]*\\{\\s*\".*?\"\\s*,\\s*\\w+\\s*,\\s*(true|false)\\s*,\\s*&[a-zA-Z_][\\w:]*::[a-zA-Z_]\\w*\\s*,\\s*\".*?\"\\s*,\\s*(NULL|nullptr)\\s*\\},?[[:blank:]]*$"]="Well-formed initializer list line (styling is valid) #ignore" + ["^[[:blank:]]*\\{[[:blank:]]*\"(SOAP-ENV|SOAP-ENC|xsi|xsd|ns1)\"[[:blank:]]*,[[:blank:]]*\"(http://[^\"]+|urn:[^\"]+)\"(?:[[:blank:]]*,[[:blank:]]*\"(http://[^\"]+|urn:[^\"]+)\")?[[:blank:]]*\\}[[:blank:]]*,?[[:blank:]]*(//.*)?$"]="Namespace initializer list line (styling is valid) #ignore" + ["^[[:blank:]]*[^[:blank:]]+[[:blank:]]*<<(.*\"[^\"]*[{}][^\"]*\".*)+[[:blank:]]*;?[[:blank:]]*$"]="Streamed brace output (styling is valid) #ignore" + + # Control TODO/FIXME rules + ["//[[:blank:]]*(TODO|FIXME)[[:blank:]]*(?!:)"]="TODO/FIXME must include description" + + # Virtual destructor enforcement + ["\\b(?:virtual[[:space:]]+)?~[[:alnum:]_]+[[:space:]]*\\([[:space:]]*\\)[[:space:]]*\\{[[:space:]]*\\}[[:space:]]*;?"]="Prefer '= default' for destructors instead of empty braces" + + # Control statements and braces + ["^[[:blank:]]*(if|else if|else|do|for|while|switch|try|catch|class|struct|namespace|case)[[:blank:]]*(\(.*\))?[[:blank:]]*\{[[:blank:]]*\S"]="Opening brace must be on its own line after statement" + ["^[[:blank:]]*[\w:<>\*&~]+[[:blank:]]+\w+::?\w*\(.*\)[[:blank:]]*(const)?[[:blank:]]*\{[[:blank:]]*\S"]="Function opening brace must be on its own line (no code after '{')" + ["^\s*\S.*\}[[:blank:]]*\S.*$"]="Closing brace must be on its own line (no code before or after '}' on the line)" + + # Brace usage enforcement + ["^[[:blank:]]*enum[[:blank:]]+(\\w+[[:blank:]]*)?\\{[[:blank:]]*[^}]*\\}[[:blank:]]*;"]="Enum opening brace must be on its own line and enum body properly formatted" + + # Spacing rules + ["\\b(if|for|while|switch|else\\s+if)\\("]="Missing space between keyword and '('" + + # Bad coding practice enforcement + ["^[[:blank:]]*using[[:blank:]]+namespace[[:blank:]]+std[[:blank:]]*;"]="Avoid using namespace std (prefer explicit qualifiers)" + ["^[[:blank:]]*namespace[[:blank:]]*\\{"]="Anonymous namespace brace must be on its own line" +) + +# Directories and files to exclude +grep_exclude_args=( + # Exclude Folders + --exclude-dir="Eluna" + --exclude-dir="Extractor_Binaries" + --exclude-dir="MangosStrings_LanguageHGenerator" + --exclude-dir="restart-scripts" + + # Exclude Files + --exclude="CMakeLists.txt" + --exclude="realmd.conf.dist.in" + --exclude="mangosd.conf.dist.in" + --exclude=".dockerignore" + --exclude=".gitattributes" + --exclude=".gitignore" + --exclude=".gitmodules" ) -for check in ${!singleLineRegexChecks[@]}; do - echo " Checking RegEx: '${check}'" - - if grep -P -r -I -n ${check} src; then - echo - echo "${singleLineRegexChecks[$check]}" - exit 1 +input_paths=("$@") +if [[ ${#input_paths[@]} -eq 0 ]]; then + input_paths=("src") +fi + +hadError=0 +declare -a triggeredDescriptions +declare -a ignoredLines=() # To store all lines matched by #ignore rules + +# First pass: collect ignored lines (to exclude later from other rules) +for check in "${!singleLineRegexChecks[@]}"; do + ruleDesc="${singleLineRegexChecks[$check]}" + if [[ "$ruleDesc" == *"#ignore"* ]]; then + # Keep original description with #ignore intact + origRuleDesc="$ruleDesc" + # Create print-friendly description without #ignore + printRuleDesc="${ruleDesc%%#*}" + + matches=$(grep -P -r -I -n "${grep_exclude_args[@]}" "${input_paths[@]}" -e "$check" 2>/dev/null) + if [[ -n "$matches" ]]; then + ignoredLines+=("$matches") + triggeredDescriptions+=("$origRuleDesc") # Store original with #ignore for summary categorization + + if $LOG_IGNORED_RULES; then + echo + echo "== Exception Rule matched: $printRuleDesc ==" + echo "$matches" + fi + fi fi done -# declare -A multiLineRegexChecks=( -# ["\n\n\n"]="Multiple blank lines detected, keep only one. Check the files above" -# ) +# Flatten ignoredLines to a single pattern (line numbers + paths) for exclusion +ignoredPattern=$(printf "%s\n" "${ignoredLines[@]}" | cut -d: -f1,2 | sort -u | tr '\n' '|' | sed 's/|$//') + +# Second pass: check non-ignored rules, excluding ignored lines from output +for check in "${!singleLineRegexChecks[@]}"; do + ruleDesc="${singleLineRegexChecks[$check]}" + if [[ "$ruleDesc" == *"#ignore"* ]]; then + # Already handled in first pass, skip here + continue + fi + + matches=$(grep -P -r -I -n "${grep_exclude_args[@]}" "${input_paths[@]}" -e "$check" 2>/dev/null) -# for check in ${!multiLineRegexChecks[@]}; do -# echo " Checking RegEx: '${check}'" + # Filter out any ignored lines from matches + if [[ -n "$matches" ]]; then + # Remove lines already caught by ignored rules + filteredMatches=$(printf "%s\n" "$matches" | grep -v -E "^($ignoredPattern):") -# if grep -Pzo -r -I ${check} src; then -# echo -# echo -# echo "${multiLineRegexChecks[$check]}" -# exit 1 -# fi -# done + if [[ -n "$filteredMatches" ]]; then + # Skip lines with streamed or quoted braces + filteredMatches=$(printf "%s\n" "$filteredMatches" | while IFS= read -r line; do + echo "$line" + done) + + if [[ -n "$filteredMatches" ]]; then + echo + echo "== Rule triggered: $ruleDesc ==" + echo "$filteredMatches" + triggeredDescriptions+=("$ruleDesc") + hadError=1 + fi + fi + fi +done echo -echo "Awesome! No issues..." +echo "------------------------------------------" +echo "Summary of Triggered Rules:" +echo "------------------------------------------" + +if [[ ${#triggeredDescriptions[@]} -eq 0 ]]; then + echo "No style violations found." +else + declare -A seen=() + exceptions=() + violations=() + + for desc in "${triggeredDescriptions[@]}"; do + # Remove leading/trailing whitespace and outer quotes if present + clean_desc="$(echo "$desc" | sed -E 's/^[[:space:]]+|[[:space:]]+$//g' | sed -E 's/^"(.*)"$/\1/')" + + # Deduplicate + [[ -n "${seen[$clean_desc]}" ]] && continue + seen["$clean_desc"]=1 + + # Check if the line ends with #ignore (with or without trailing space) + if [[ "$desc" =~ [[:space:]]*#ignore$ ]]; then + # Remove #ignore for printing + exceptions+=("$(echo "$clean_desc" | sed -E 's/[[:space:]]*#ignore$//')") + else + violations+=("$clean_desc") + fi + done + + echo "Exception Rules (Informational Only):" + echo "----" + if [[ ${#exceptions[@]} -eq 0 ]]; then + echo "(none)" + else + for e in "${exceptions[@]}"; do + echo "$e" + done + fi + + echo "------------------------------------------" + echo "Violations:" + echo "----" + if [[ ${#violations[@]} -eq 0 ]]; then + echo "(none)" + else + for v in "${violations[@]}"; do + echo "$v" + done + fi +fi + +exit $hadError diff --git a/apps/ci/ci-compile.sh b/apps/ci/ci-compile.sh index a8669e58c..7fe5b1b01 100644 --- a/apps/ci/ci-compile.sh +++ b/apps/ci/ci-compile.sh @@ -3,14 +3,14 @@ set -e # Check for & make directories -time test -d _build || mkdir _build -time test -d _install || mkdir _install +test -d _build || mkdir _build +test -d _install || mkdir _install # Move to build folder -time cd _build +cd _build # Run CMake Configurations -time cmake .. -DCMAKE_INSTALL_PREFIX=../_install -DBUILD_TOOLS:BOOL=1 -DBUILD_MANGOSD:BOOL=1 -DBUILD_REALMD:BOOL=1 -DSOAP:BOOL=1 -DSCRIPT_LIB_ELUNA:BOOL=1 -DSCRIPT_LIB_SD3:BOOL=1 -DPLAYERBOTS:BOOL=1 -DUSE_STORMLIB:BOOL=1 +cmake .. -DCMAKE_INSTALL_PREFIX=../_install -DCMAKE_C_COMPILER=/usr/bin/clang -DCMAKE_CXX_COMPILER=/usr/bin/clang++ -DBUILD_TOOLS:BOOL=1 -DBUILD_MANGOSD:BOOL=1 -DBUILD_REALMD:BOOL=1 -DSOAP:BOOL=1 -DSCRIPT_LIB_ELUNA:BOOL=1 -DSCRIPT_LIB_SD3:BOOL=1 -DPLAYERBOTS:BOOL=1 -DUSE_STORMLIB:BOOL=1 # Compile the Project -time make -j 6 +make -j$(nproc) diff --git a/apps/ci/ci-compiler-update.sh b/apps/ci/ci-compiler-update.sh deleted file mode 100644 index f281f376b..000000000 --- a/apps/ci/ci-compiler-update.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -# Update to Clang Compilers -time sudo update-alternatives --install /usr/bin/cc cc /usr/bin/clang 100 -time sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang 100 diff --git a/apps/ci/ci-submodule-update.sh b/apps/ci/ci-submodule-update.sh deleted file mode 100644 index 4ebb10efe..000000000 --- a/apps/ci/ci-submodule-update.sh +++ /dev/null @@ -1,7 +0,0 @@ -#!/bin/bash - -set -e - -# Check for Submodule Updates -git submodule init -git submodule update diff --git a/apps/styling_tools/fix_statement_spacing.sh b/apps/styling_tools/fix_statement_spacing.sh new file mode 100644 index 000000000..6e466b87b --- /dev/null +++ b/apps/styling_tools/fix_statement_spacing.sh @@ -0,0 +1,47 @@ +#!/bin/bash + +# +# Fix Statement Spacing for getMaNGOS +# Script written by Meltie2013 (https://github.com/Meltie2013) +# +# Copyright: 2025 +# Website: https://getmangos.eu/ +# +# Script Type: Bash +# +# Co-authors Area: +# +# Note from the author: Anyone is free to use this script but is asked to keep the original author name and GitHub url in the header. +# You can add co-authors to the header when the script is updated or changed for your project needs. Removing the original author +# from the header, will result in a DMCA (take-down). +# +# This script is viewed under the GPL-2.0 license and shall not be changed unless authorized by the original author. +# + +# Fixes missing space between control statement keywords and '(' + +# List of statement keywords to fix +keywords="if|else[[:blank:]]+if|for|while|switch" + +for file in $(find ./src -type f \( -name "*.cpp" -o -name "*.h" \)); do + temp_file="${file}.tmp" + cp "$file" "$temp_file" + + changed=false + + IFS='|' read -ra KW_ARR <<< "$keywords" + for kw in "${KW_ARR[@]}"; do + # Fix keyword immediately followed by '(' with no space + sed -E "s/\b($kw)\(/\1 (/g" "$temp_file" > "$temp_file.tmp" && mv "$temp_file.tmp" "$temp_file" + if ! diff -q "$file" "$temp_file" >/dev/null; then + changed=true + fi + done + + if $changed; then + mv "$temp_file" "$file" + echo "Fixed spacing in: $file" + else + rm "$temp_file" + fi +done diff --git a/apps/whitespace_remover/whitespace_remover.sh b/apps/whitespace_remover/whitespace_remover.sh index fe3aeea6a..f6cea6fb3 100755 --- a/apps/whitespace_remover/whitespace_remover.sh +++ b/apps/whitespace_remover/whitespace_remover.sh @@ -1,6 +1,14 @@ # Required files -find -name '*.cpp' -print0 | xargs -r0 sed -e 's/[[:blank:]]\+$//' -i -find -name '*.h' -print0 | xargs -r0 sed -e 's/[[:blank:]]\+$//' -i + +# Find all .cpp files and process them: +# - Remove trailing whitespace at the end of lines (spaces or tabs) +# - Replace every tab character with 4 spaces +find -name '*.cpp' -print0 | xargs -r0 sed -e 's/[[:blank:]]\+$//' -e 's/\t/ /g' -i + +# Find all .h files and process them the same way: +# - Remove trailing whitespace at the end of lines (spaces or tabs) +# - Replace every tab character with 4 spaces +find -name '*.h' -print0 | xargs -r0 sed -e 's/[[:blank:]]\+$//' -e 's/\t/ /g' -i # Optional files - uncomment lines below to add them. #find -name '*.txt' -print0 | xargs -r0 sed -e 's/[[:blank:]]\+$//' -i