From 3cefc9c0c4b6f6630ba12fb6f6ff9cef9a33e8a5 Mon Sep 17 00:00:00 2001 From: o1rik Date: Sun, 8 Feb 2026 22:52:58 +0100 Subject: [PATCH 01/53] fix(hz): HumanitZ 1.0 new binary path (#4873) --- lgsm/config-default/config-lgsm/hzserver/_default.cfg | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/config-default/config-lgsm/hzserver/_default.cfg b/lgsm/config-default/config-lgsm/hzserver/_default.cfg index 61403a6d2..d2e63e692 100644 --- a/lgsm/config-default/config-lgsm/hzserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/hzserver/_default.cfg @@ -163,9 +163,9 @@ glibc="2.17" # Edit with care ## Game Server Directories -systemdir="${serverfiles}/TSSGame" +systemdir="${serverfiles}/HumanitZServer" executabledir="${systemdir}/Binaries/Linux" -executable="./TSSGameServer-Linux-Shipping" +executable="./HumanitZServer-Linux-Shipping" servercfgdir="${systemdir}" servercfg="GameServerSettings.ini" servercfgdefault="GameUserSettings.ini" From 30dcde03cc8dbbcfcc64e12369836de90dda885b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marcell=20P=C3=BCnk=C3=B6sd?= Date: Thu, 12 Mar 2026 23:28:12 +0100 Subject: [PATCH 02/53] fix(scpsl): Add libicu76 as a dependency of scpsl (#4869) Co-authored-by: Daniel Gibbs --- lgsm/data/debian-13.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 2ca56633f..e7a622a7e 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -100,7 +100,7 @@ rw,openjdk-25-jre samp sb sbots -scpsl,mono-complete +scpsl,mono-complete,libicu76 scpslsm,mono-complete sdtd,telnet,expect,libxml2-utils sf From e1cbee07a53a423b36ed1d3421bb5c6c883c5210 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 12 Mar 2026 22:30:36 +0000 Subject: [PATCH 03/53] chore: synced local '.github/' with remote 'general/.github/' (#4852) --- .github/workflows/action-prettier.yml | 2 +- .github/workflows/action-super-linter.yml | 6 ++++-- .../action-update-copyright-years-in-license-file.yml | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/.github/workflows/action-prettier.yml b/.github/workflows/action-prettier.yml index a7e0a7172..f5d51a44a 100644 --- a/.github/workflows/action-prettier.yml +++ b/.github/workflows/action-prettier.yml @@ -19,7 +19,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: persist-credentials: false diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index a2b12fca4..31b2fa949 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -25,7 +25,7 @@ jobs: steps: - name: Checkout code - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: # super-linter needs the full git history to get the # list of files that changed across commits @@ -41,11 +41,13 @@ jobs: env: # To report GitHub Actions status checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + VALIDATE_BIOME_FORMAT: false + VALIDATE_BIOME_LINT: false VALIDATE_GITHUB_ACTIONS_ZIZMOR: false VALIDATE_JSCPD: false VALIDATE_JSON_PRETTIER: false VALIDATE_MARKDOWN_PRETTIER: false VALIDATE_NATURAL_LANGUAGE: false VALIDATE_SHELL_SHFMT: false - VALIDATE_TERRAFORM_TERRASCAN: false + VALIDATE_TRIVY: false VALIDATE_YAML_PRETTIER: false diff --git a/.github/workflows/action-update-copyright-years-in-license-file.yml b/.github/workflows/action-update-copyright-years-in-license-file.yml index 7ee528ca9..ab1549f0e 100644 --- a/.github/workflows/action-update-copyright-years-in-license-file.yml +++ b/.github/workflows/action-update-copyright-years-in-license-file.yml @@ -13,7 +13,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v5 + uses: actions/checkout@v6 with: fetch-depth: 0 persist-credentials: false From fef128fb7d31f01a776ec60e17cb44e8de570563 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Thu, 12 Mar 2026 22:37:36 +0000 Subject: [PATCH 04/53] fix (alerts): Alerts on update uses the old game server version not the new one (#4854) * feat: refactor update comparison output for consistency and clarity - Replaced direct echo statements with fn_print functions for uniformity in output formatting across multiple update scripts. - Ensured lockfile creation uses the correct syntax for variable expansion. - Moved lock file to the same location to ensure monitor doesnt reboot at the wrong time - Updated remote build information display to enhance readability and maintain consistency in logging. - Removed unnecessary echo commands to streamline the output process. * Refactor remote build version handling across multiple modules - Updated variable names from 'remotebuildversion' to 'remotebuild' for consistency. - Adjusted logic to check for remote build availability using the new variable name. - Modified output messages to reflect the change in variable naming. - Ensured all modules (update_mc.sh, update_mcb.sh, update_mta.sh, update_pmc.sh, update_ts3.sh, update_ut99.sh, update_vints.sh, update_xnt.sh) are aligned with the new naming convention for better readability and maintainability. * fix(alert): resolve issue with servername not always being listed in title * Moved `info_distro.sh`, `info_game.sh`, and `info_messages.sh` calls to the top of the `fn_alert_log` function for better clarity. * Updated `alerticon` assignment to maintain consistency in alert information handling. * fix(alert_discord): remove "More info" field from Discord alert JSON * Eliminated the "More info" field to streamline the alert message. * This change enhances the clarity of the alert by focusing on essential information. * fix(alert): improve update alert messaging for clarity * Updated alert messages in `fn_alert_update` and `fn_alert_update_failed` for better readability. * Changed alert action from `update-request` to `update-restart-request` in `fn_monitor_check_update_source`. * remove inline * fix(alert): Correct grammar in update alert message * Changed "an LinuxGSM update" to "a LinuxGSM update" for grammatical accuracy. * typo * fix(alert_discord): Add inline property to "Is my Game Server Online?" field * Ensures proper formatting of the Discord alert message. * Improves the display of the server status information. * fix(pd): increase timeout for termbin.com connection * fix(alert_discord): reorder fields in Discord alert JSON * Changed the order of fields in the Discord alert JSON structure. * Updated the "More info" and "Is my Game Server Online?" fields for better clarity. * revert back to factorio.com Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Standardizes alert messages across platforms Ensures consistency in alert messages across Discord, NTFY, Pushover, Rocketchat, Slack, and Telegram. Updates Discord alerts to include server hostname and time, removes redundant formatting. Standardizes plain-text alert formatting for NTFY. Refactors Pushover messages to use consistent HTML formatting. Streamlines Rocketchat and Slack messages by removing duplicate server info and adding optional link support. * Removes Hostname from alert messages Removes the Hostname field from various alert messages (Discord, Gotify, IFTTT, ntfy, Pushbullet, Pushover, Rocketchat, Slack, Telegram). The hostname was deemed redundant or unnecessary in the context of these alerts. Relates to #4696 * Configures shellcheckrc filename Configures the Super-Linter action to use `.shellcheckrc` as the BASH_FILE_NAME. This ensures that shellcheck uses the correct configuration file for bash script linting. Fixes #4696 * Disables shellcheck errors and removes variable Disables specific shellcheck errors to allow certain coding patterns and removes an unused variable from the super-linter workflow. This improves the linter's signal-to-noise ratio and reduces unnecessary checks. Relates to #4696 * Fixes and improves server list validation scripts Addresses issues in the server list validation scripts: - Fixes potential issues with parsing curl custom arguments in telegram alerts. - Corrects the shortname array generation. - Implements more robust checks for validating game icons. - Ensures the consistency of server counts across different CSV files. * Fixes glibc check and mod selection logic Corrects glibc version comparison to properly handle version strings. Improves mod installation and removal by validating user input against available options, providing a more robust selection process. This prevents errors caused by invalid mod names and enhances the user experience. Updates arithmetic expression syntax for better compatibility. * Fixes cache control for dev-debug mode Updates the handling of cache control headers in dev-debug mode. The `nocache` variable is changed to an array to correctly pass multiple headers to `curl`. This resolves issues with cached versions of files being used when dev-debug is enabled, ensuring that the latest versions are always fetched. Fixes #4696 * Allows spaces in steamcmdcommand variable Parses steamcmdcommand as an array to allow spaces in the variable. This prevents issues when the user wants to pass arguments with spaces to the steamcmd executable. * Addresses various script improvements Addresses multiple improvements across various scripts: - Fixes Valheim unstripped_corlib override by commenting out the lines in the config files. - Improves process identification for source and goldsrc engines using `pgrep`. - Enhances backup file identification using `find` with `-maxdepth 1` and `-type f`. - Fixes glibc version comparison logic in multiple files. - Improves UT2K4 key installation script by using printf for writing the key to the file. - Corrects the mod info extraction logic to correctly identify mod entries. - Improves amxmodx file installation/removal logic to prevent duplicate entries. - Fixes server info retrieval to handle spaces in the server list. Relates to #4696 * Fixes mono repo install exit code check Corrects the mono repo install exit code check to use the dedicated monorepoexitcode variable, ensuring accurate error detection. Updates the exit trap to preserve the original exit status, preventing potential loss of information when handling script termination. * Refactors and reorders core modules Improves module loading by reordering and refactoring the core modules. This change addresses inconsistencies and improves the overall structure of how core modules are handled within the system. Some fix scripts were renamed to match the module name. * Makes scripts executable Changes file permissions to make shell scripts executable. This ensures that the scripts can be run directly. Addresses a pre-existing issue. Related to #4696 * Adds explicit permissions to workflows Specifies explicit permissions for GitHub Actions workflows to enhance security and control access to resources. This ensures that each workflow only has the necessary permissions, following the principle of least privilege. * Fixes output redirection and URL parsing Corrects output redirection in GitHub Actions workflows by enclosing the $GITHUB_OUTPUT variable in quotes, preventing potential issues with variable expansion. Ensures proper URL parsing in workflows by enclosing the URL within quotes, addressing potential parsing errors. Fixes #4696 * Applies code formatting for consistency Applies Prettier formatting to the codebase for improved readability and consistency. Addresses minor code style inconsistencies across several files. * Fixes minor formatting and logic issues Addresses various minor issues including: - Standardizes indentation in `.editorconfig` for different file types. - Simplifies Prettier configuration. - Updates image links in `README.md`. - Ensures newline character at end of `.csv` files. - Corrects a conditional statement in `command_fastdl.sh`. - Corrects a conditional statement in `info_messages.sh`. - Updates server query protocols in `query_gsquery.py`. * Configures and disables linters Adds YAML linting configuration and disables unnecessary linters to streamline the CI/CD process and reduce noise from irrelevant checks. * Improves documentation and linting Updates documentation links to be enclosed in angle brackets, preventing markdown rendering issues. Configures markdownlint to align with repository standards and avoid common false positives. The updated links in the documentation ensure they are correctly interpreted by markdown parsers, improving user experience. The markdownlint configuration fine-tunes linting rules to better match the project's existing style and conventions, reducing noise from irrelevant warnings. * Fixes typos and improves code consistency Addresses various typos and inconsistencies across multiple files, enhancing code readability and maintainability. Adds codespell and flake8 configurations for linting. Relates to #4696 * Excludes workflow files from Prettier formatting Prevents Prettier from formatting workflow files due to GitHub token restrictions, as the token used by the Prettier auto-commit action lacks permissions to update files within the `.github/workflows/` directory. * chore(prettier): format code * Updates Super-Linter configuration Improves Super-Linter's reliability by switching to linting the entire codebase instead of relying on git history. This change also addresses potential transient fetch failures from GitHub. Additionally, this commit expands the ignored paths in codespell and disables some linters to improve performance and reduce false positives. --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: dgibbs64 --- .devcontainer/devcontainer.json | 56 ++--- .editorconfig | 17 +- .github/linters/.codespellrc | 11 + .github/linters/.flake8 | 2 + .github/linters/.markdown-lint.yml | 23 ++ .github/linters/.shellcheckrc | 1 + .github/linters/.yaml-lint.yml | 25 +++ .github/pull_request_template.md | 30 +-- .github/workflows/action-super-linter.yml | 8 +- .github/workflows/add-to-project.yml | 2 + .../details-check-generate-matrix.sh | 10 +- .github/workflows/details-check.yml | 7 +- .github/workflows/git-sync.yml | 2 + .github/workflows/potential-duplicates.yml | 4 + .../serverlist-validate-game-icons.sh | 12 +- .github/workflows/serverlist-validate.sh | 9 +- .github/workflows/serverlist-validate.yml | 3 + .github/workflows/trigger-docker-build.yml | 2 + .github/workflows/update-check.yml | 4 +- ...update-copyright-years-in-license-file.yml | 4 + .github/workflows/version-check.sh | 0 .prettierignore | 3 + .prettierrc | 2 +- .prettierrc.json | 2 +- .shellcheckrc | 2 +- .vscode/extensions.json | 20 +- CODE_OF_CONDUCT.md | 30 +-- CONTRIBUTING.md | 133 ++++++----- README.md | 32 +-- .../config-lgsm/armarserver/_default.cfg | 2 +- .../config-lgsm/necserver/_default.cfg | 2 +- .../config-lgsm/ns2cserver/_default.cfg | 2 +- .../config-lgsm/ns2server/_default.cfg | 2 +- .../config-lgsm/pwserver/_default.cfg | 2 +- lgsm/data/name-left.csv | 2 +- lgsm/data/name-right.csv | 2 +- lgsm/modules/README.md | 18 +- lgsm/modules/alert.sh | 61 ++++-- lgsm/modules/alert_discord.sh | 21 +- lgsm/modules/alert_email.sh | 0 lgsm/modules/alert_gotify.sh | 2 +- lgsm/modules/alert_ifttt.sh | 2 +- lgsm/modules/alert_ntfy.sh | 26 ++- lgsm/modules/alert_pushbullet.sh | 2 +- lgsm/modules/alert_pushover.sh | 4 +- lgsm/modules/alert_rocketchat.sh | 66 +----- lgsm/modules/alert_slack.sh | 96 +------- lgsm/modules/alert_telegram.sh | 10 +- lgsm/modules/check.sh | 0 lgsm/modules/check_config.sh | 0 lgsm/modules/check_deps.sh | 6 +- lgsm/modules/check_executable.sh | 0 lgsm/modules/check_gamedig.sh | 0 lgsm/modules/check_glibc.sh | 2 +- lgsm/modules/check_ip.sh | 0 lgsm/modules/check_last_update.sh | 1 + lgsm/modules/check_logs.sh | 0 lgsm/modules/check_permissions.sh | 2 +- lgsm/modules/check_root.sh | 0 lgsm/modules/check_status.sh | 0 lgsm/modules/check_steamcmd.sh | 0 lgsm/modules/check_system_dir.sh | 0 lgsm/modules/check_system_requirements.sh | 2 +- lgsm/modules/check_tmuxception.sh | 0 lgsm/modules/check_version.sh | 0 lgsm/modules/command_backup.sh | 0 lgsm/modules/command_check_update.sh | 0 lgsm/modules/command_console.sh | 0 lgsm/modules/command_debug.sh | 2 +- lgsm/modules/command_details.sh | 2 +- lgsm/modules/command_dev_clear_modules.sh | 0 lgsm/modules/command_dev_debug.sh | 0 lgsm/modules/command_dev_detect_deps.sh | 0 lgsm/modules/command_dev_detect_glibc.sh | 2 +- lgsm/modules/command_dev_detect_ldd.sh | 0 .../command_dev_parse_distro_details.sh | 0 .../modules/command_dev_parse_game_details.sh | 0 lgsm/modules/command_dev_query_raw.sh | 8 +- lgsm/modules/command_dev_ui.sh | 0 lgsm/modules/command_fastdl.sh | 2 +- lgsm/modules/command_install.sh | 0 lgsm/modules/command_install_resources_mta.sh | 0 lgsm/modules/command_mods_install.sh | 23 +- lgsm/modules/command_mods_remove.sh | 21 +- lgsm/modules/command_mods_update.sh | 0 lgsm/modules/command_monitor.sh | 4 +- lgsm/modules/command_postdetails.sh | 4 +- lgsm/modules/command_restart.sh | 0 lgsm/modules/command_send.sh | 0 lgsm/modules/command_skeleton.sh | 4 +- lgsm/modules/command_start.sh | 0 lgsm/modules/command_stop.sh | 4 +- lgsm/modules/command_test_alert.sh | 0 lgsm/modules/command_ts3_server_pass.sh | 0 lgsm/modules/command_update.sh | 0 lgsm/modules/command_update_linuxgsm.sh | 39 ++-- lgsm/modules/command_validate.sh | 0 lgsm/modules/command_wipe.sh | 0 lgsm/modules/compress_unreal_maps.sh | 0 lgsm/modules/core_dl.sh | 38 ++-- lgsm/modules/core_exit.sh | 0 lgsm/modules/core_getopt.sh | 0 lgsm/modules/core_github.sh | 0 lgsm/modules/core_legacy.sh | 2 +- lgsm/modules/core_logs.sh | 0 lgsm/modules/core_messages.sh | 2 +- lgsm/modules/core_modules.sh | 206 +++++++++--------- lgsm/modules/core_steamcmd.sh | 22 +- lgsm/modules/core_trap.sh | 6 +- lgsm/modules/fix.sh | 0 lgsm/modules/fix_ark.sh | 4 +- lgsm/modules/fix_arma3.sh | 0 lgsm/modules/fix_av.sh | 0 lgsm/modules/fix_bo.sh | 0 lgsm/modules/fix_cmw.sh | 0 lgsm/modules/fix_csgo.sh | 0 lgsm/modules/fix_dst.sh | 2 +- lgsm/modules/fix_hw.sh | 0 lgsm/modules/fix_ins.sh | 0 lgsm/modules/fix_kf.sh | 0 lgsm/modules/fix_kf2.sh | 0 lgsm/modules/fix_mcb.sh | 0 lgsm/modules/fix_mta.sh | 0 lgsm/modules/fix_nmrih.sh | 0 lgsm/modules/fix_onset.sh | 2 +- lgsm/modules/fix_pvr.sh | 0 lgsm/modules/fix_ro.sh | 0 lgsm/modules/fix_rust.sh | 2 +- lgsm/modules/fix_rw.sh | 0 lgsm/modules/fix_samp.sh | 0 lgsm/modules/fix_sdtd.sh | 0 lgsm/modules/fix_sfc.sh | 0 lgsm/modules/fix_sm.sh | 0 lgsm/modules/fix_sof2.sh | 2 +- lgsm/modules/fix_squad.sh | 0 lgsm/modules/fix_st.sh | 2 +- lgsm/modules/fix_steamcmd.sh | 0 lgsm/modules/fix_terraria.sh | 0 lgsm/modules/fix_tf2.sh | 0 lgsm/modules/fix_ts3.sh | 0 lgsm/modules/fix_unt.sh | 2 +- lgsm/modules/fix_ut.sh | 0 lgsm/modules/fix_ut2k4.sh | 0 lgsm/modules/fix_ut3.sh | 0 lgsm/modules/fix_vh.sh | 6 +- lgsm/modules/fix_wurm.sh | 0 lgsm/modules/fix_xnt.sh | 0 lgsm/modules/fix_zmr.sh | 0 lgsm/modules/info_distro.sh | 14 +- lgsm/modules/info_game.sh | 6 +- lgsm/modules/info_messages.sh | 6 +- lgsm/modules/info_stats.sh | 0 lgsm/modules/install_complete.sh | 0 lgsm/modules/install_config.sh | 4 +- lgsm/modules/install_dst_token.sh | 0 lgsm/modules/install_eula.sh | 0 lgsm/modules/install_factorio_save.sh | 0 lgsm/modules/install_gslt.sh | 0 lgsm/modules/install_header.sh | 0 lgsm/modules/install_logs.sh | 0 lgsm/modules/install_mta_resources.sh | 0 lgsm/modules/install_retry.sh | 0 lgsm/modules/install_server_dir.sh | 0 lgsm/modules/install_server_files.sh | 0 lgsm/modules/install_squad_license.sh | 0 lgsm/modules/install_stats.sh | 0 lgsm/modules/install_steamcmd.sh | 0 lgsm/modules/install_ts3db.sh | 0 lgsm/modules/install_ut2k4_key.sh | 2 +- lgsm/modules/mods_core.sh | 33 ++- lgsm/modules/mods_list.sh | 6 +- lgsm/modules/query_gamedig.sh | 2 +- lgsm/modules/query_gsquery.py | 184 ++++++++++------ lgsm/modules/update_fctr.sh | 100 +++++---- lgsm/modules/update_jk2.sh | 68 +++--- lgsm/modules/update_mc.sh | 76 +++---- lgsm/modules/update_mcb.sh | 76 +++---- lgsm/modules/update_mta.sh | 68 +++--- lgsm/modules/update_pmc.sh | 70 +++--- lgsm/modules/update_steamcmd.sh | 0 lgsm/modules/update_ts3.sh | 68 +++--- lgsm/modules/update_ut99.sh | 70 +++--- lgsm/modules/update_vints.sh | 73 +++---- lgsm/modules/update_xnt.sh | 69 +++--- linuxgsm.sh | 3 +- package.json | 50 ++--- 186 files changed, 1155 insertions(+), 1097 deletions(-) create mode 100644 .github/linters/.codespellrc create mode 100644 .github/linters/.flake8 create mode 100644 .github/linters/.markdown-lint.yml create mode 100644 .github/linters/.shellcheckrc create mode 100644 .github/linters/.yaml-lint.yml mode change 100644 => 100755 .github/workflows/version-check.sh create mode 100644 .prettierignore mode change 100644 => 100755 lgsm/modules/alert.sh mode change 100644 => 100755 lgsm/modules/alert_discord.sh mode change 100644 => 100755 lgsm/modules/alert_email.sh mode change 100644 => 100755 lgsm/modules/alert_gotify.sh mode change 100644 => 100755 lgsm/modules/alert_ifttt.sh mode change 100644 => 100755 lgsm/modules/alert_ntfy.sh mode change 100644 => 100755 lgsm/modules/alert_pushbullet.sh mode change 100644 => 100755 lgsm/modules/alert_pushover.sh mode change 100644 => 100755 lgsm/modules/alert_rocketchat.sh mode change 100644 => 100755 lgsm/modules/alert_slack.sh mode change 100644 => 100755 lgsm/modules/alert_telegram.sh mode change 100644 => 100755 lgsm/modules/check.sh mode change 100644 => 100755 lgsm/modules/check_config.sh mode change 100644 => 100755 lgsm/modules/check_deps.sh mode change 100644 => 100755 lgsm/modules/check_executable.sh mode change 100644 => 100755 lgsm/modules/check_gamedig.sh mode change 100644 => 100755 lgsm/modules/check_glibc.sh mode change 100644 => 100755 lgsm/modules/check_ip.sh mode change 100644 => 100755 lgsm/modules/check_last_update.sh mode change 100644 => 100755 lgsm/modules/check_logs.sh mode change 100644 => 100755 lgsm/modules/check_permissions.sh mode change 100644 => 100755 lgsm/modules/check_root.sh mode change 100644 => 100755 lgsm/modules/check_status.sh mode change 100644 => 100755 lgsm/modules/check_steamcmd.sh mode change 100644 => 100755 lgsm/modules/check_system_dir.sh mode change 100644 => 100755 lgsm/modules/check_system_requirements.sh mode change 100644 => 100755 lgsm/modules/check_tmuxception.sh mode change 100644 => 100755 lgsm/modules/check_version.sh mode change 100644 => 100755 lgsm/modules/command_backup.sh mode change 100644 => 100755 lgsm/modules/command_check_update.sh mode change 100644 => 100755 lgsm/modules/command_console.sh mode change 100644 => 100755 lgsm/modules/command_debug.sh mode change 100644 => 100755 lgsm/modules/command_details.sh mode change 100644 => 100755 lgsm/modules/command_dev_clear_modules.sh mode change 100644 => 100755 lgsm/modules/command_dev_debug.sh mode change 100644 => 100755 lgsm/modules/command_dev_detect_deps.sh mode change 100644 => 100755 lgsm/modules/command_dev_detect_glibc.sh mode change 100644 => 100755 lgsm/modules/command_dev_detect_ldd.sh mode change 100644 => 100755 lgsm/modules/command_dev_parse_distro_details.sh mode change 100644 => 100755 lgsm/modules/command_dev_parse_game_details.sh mode change 100644 => 100755 lgsm/modules/command_dev_query_raw.sh mode change 100644 => 100755 lgsm/modules/command_dev_ui.sh mode change 100644 => 100755 lgsm/modules/command_fastdl.sh mode change 100644 => 100755 lgsm/modules/command_install.sh mode change 100644 => 100755 lgsm/modules/command_install_resources_mta.sh mode change 100644 => 100755 lgsm/modules/command_mods_install.sh mode change 100644 => 100755 lgsm/modules/command_mods_remove.sh mode change 100644 => 100755 lgsm/modules/command_mods_update.sh mode change 100644 => 100755 lgsm/modules/command_monitor.sh mode change 100644 => 100755 lgsm/modules/command_postdetails.sh mode change 100644 => 100755 lgsm/modules/command_restart.sh mode change 100644 => 100755 lgsm/modules/command_send.sh mode change 100644 => 100755 lgsm/modules/command_skeleton.sh mode change 100644 => 100755 lgsm/modules/command_start.sh mode change 100644 => 100755 lgsm/modules/command_stop.sh mode change 100644 => 100755 lgsm/modules/command_test_alert.sh mode change 100644 => 100755 lgsm/modules/command_ts3_server_pass.sh mode change 100644 => 100755 lgsm/modules/command_update.sh mode change 100644 => 100755 lgsm/modules/command_update_linuxgsm.sh mode change 100644 => 100755 lgsm/modules/command_validate.sh mode change 100644 => 100755 lgsm/modules/command_wipe.sh mode change 100644 => 100755 lgsm/modules/compress_unreal_maps.sh mode change 100644 => 100755 lgsm/modules/core_dl.sh mode change 100644 => 100755 lgsm/modules/core_exit.sh mode change 100644 => 100755 lgsm/modules/core_getopt.sh mode change 100644 => 100755 lgsm/modules/core_github.sh mode change 100644 => 100755 lgsm/modules/core_legacy.sh mode change 100644 => 100755 lgsm/modules/core_logs.sh mode change 100644 => 100755 lgsm/modules/core_messages.sh mode change 100644 => 100755 lgsm/modules/core_modules.sh mode change 100644 => 100755 lgsm/modules/core_steamcmd.sh mode change 100644 => 100755 lgsm/modules/core_trap.sh mode change 100644 => 100755 lgsm/modules/fix.sh mode change 100644 => 100755 lgsm/modules/fix_ark.sh mode change 100644 => 100755 lgsm/modules/fix_arma3.sh mode change 100644 => 100755 lgsm/modules/fix_av.sh mode change 100644 => 100755 lgsm/modules/fix_bo.sh mode change 100644 => 100755 lgsm/modules/fix_cmw.sh mode change 100644 => 100755 lgsm/modules/fix_csgo.sh mode change 100644 => 100755 lgsm/modules/fix_dst.sh mode change 100644 => 100755 lgsm/modules/fix_hw.sh mode change 100644 => 100755 lgsm/modules/fix_ins.sh mode change 100644 => 100755 lgsm/modules/fix_kf.sh mode change 100644 => 100755 lgsm/modules/fix_kf2.sh mode change 100644 => 100755 lgsm/modules/fix_mcb.sh mode change 100644 => 100755 lgsm/modules/fix_mta.sh mode change 100644 => 100755 lgsm/modules/fix_nmrih.sh mode change 100644 => 100755 lgsm/modules/fix_onset.sh mode change 100644 => 100755 lgsm/modules/fix_pvr.sh mode change 100644 => 100755 lgsm/modules/fix_ro.sh mode change 100644 => 100755 lgsm/modules/fix_rust.sh mode change 100644 => 100755 lgsm/modules/fix_rw.sh mode change 100644 => 100755 lgsm/modules/fix_samp.sh mode change 100644 => 100755 lgsm/modules/fix_sdtd.sh mode change 100644 => 100755 lgsm/modules/fix_sfc.sh mode change 100644 => 100755 lgsm/modules/fix_sm.sh mode change 100644 => 100755 lgsm/modules/fix_sof2.sh mode change 100644 => 100755 lgsm/modules/fix_squad.sh mode change 100644 => 100755 lgsm/modules/fix_st.sh mode change 100644 => 100755 lgsm/modules/fix_steamcmd.sh mode change 100644 => 100755 lgsm/modules/fix_terraria.sh mode change 100644 => 100755 lgsm/modules/fix_tf2.sh mode change 100644 => 100755 lgsm/modules/fix_ts3.sh mode change 100644 => 100755 lgsm/modules/fix_unt.sh mode change 100644 => 100755 lgsm/modules/fix_ut.sh mode change 100644 => 100755 lgsm/modules/fix_ut2k4.sh mode change 100644 => 100755 lgsm/modules/fix_ut3.sh mode change 100644 => 100755 lgsm/modules/fix_vh.sh mode change 100644 => 100755 lgsm/modules/fix_wurm.sh mode change 100644 => 100755 lgsm/modules/fix_xnt.sh mode change 100644 => 100755 lgsm/modules/fix_zmr.sh mode change 100644 => 100755 lgsm/modules/info_distro.sh mode change 100644 => 100755 lgsm/modules/info_game.sh mode change 100644 => 100755 lgsm/modules/info_messages.sh mode change 100644 => 100755 lgsm/modules/info_stats.sh mode change 100644 => 100755 lgsm/modules/install_complete.sh mode change 100644 => 100755 lgsm/modules/install_config.sh mode change 100644 => 100755 lgsm/modules/install_dst_token.sh mode change 100644 => 100755 lgsm/modules/install_eula.sh mode change 100644 => 100755 lgsm/modules/install_factorio_save.sh mode change 100644 => 100755 lgsm/modules/install_gslt.sh mode change 100644 => 100755 lgsm/modules/install_header.sh mode change 100644 => 100755 lgsm/modules/install_logs.sh mode change 100644 => 100755 lgsm/modules/install_mta_resources.sh mode change 100644 => 100755 lgsm/modules/install_retry.sh mode change 100644 => 100755 lgsm/modules/install_server_dir.sh mode change 100644 => 100755 lgsm/modules/install_server_files.sh mode change 100644 => 100755 lgsm/modules/install_squad_license.sh mode change 100644 => 100755 lgsm/modules/install_stats.sh mode change 100644 => 100755 lgsm/modules/install_steamcmd.sh mode change 100644 => 100755 lgsm/modules/install_ts3db.sh mode change 100644 => 100755 lgsm/modules/install_ut2k4_key.sh mode change 100644 => 100755 lgsm/modules/mods_core.sh mode change 100644 => 100755 lgsm/modules/mods_list.sh mode change 100644 => 100755 lgsm/modules/query_gamedig.sh mode change 100644 => 100755 lgsm/modules/update_fctr.sh mode change 100644 => 100755 lgsm/modules/update_jk2.sh mode change 100644 => 100755 lgsm/modules/update_mc.sh mode change 100644 => 100755 lgsm/modules/update_mcb.sh mode change 100644 => 100755 lgsm/modules/update_mta.sh mode change 100644 => 100755 lgsm/modules/update_pmc.sh mode change 100644 => 100755 lgsm/modules/update_steamcmd.sh mode change 100644 => 100755 lgsm/modules/update_ts3.sh mode change 100644 => 100755 lgsm/modules/update_ut99.sh mode change 100644 => 100755 lgsm/modules/update_vints.sh mode change 100644 => 100755 lgsm/modules/update_xnt.sh diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 506b50754..32c844ac7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,30 +1,30 @@ { - "name": "BASH Dev Container", - "image": "mcr.microsoft.com/devcontainers/base:ubuntu", - "features": { - "ghcr.io/devcontainers-community/npm-features/prettier:1": { - "plugins": "prettier-plugin-sh" - }, - "ghcr.io/devcontainers-extra/features/actionlint:1": {}, - "ghcr.io/devcontainers-extra/features/checkov:1": {}, - "ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {}, - "ghcr.io/devcontainers-extra/features/shellcheck:1": {}, - "ghcr.io/devcontainers-extra/features/yamllint:2": {}, - "ghcr.io/devcontainers/features/github-cli:1": {} - }, - "customizations": { - "vscode": { - "extensions": [ - "DavidAnson.vscode-markdownlint", - "editorconfig.editorconfig", - "esbenp.prettier-vscode", - "github.vscode-github-actions", - "GitHub.vscode-pull-request-github", - "redhat.vscode-yaml", - "timonwong.shellcheck", - "yzhang.markdown-all-in-one" - ] - } - }, - "postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template" + "name": "BASH Dev Container", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers-community/npm-features/prettier:1": { + "plugins": "prettier-plugin-sh" + }, + "ghcr.io/devcontainers-extra/features/actionlint:1": {}, + "ghcr.io/devcontainers-extra/features/checkov:1": {}, + "ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {}, + "ghcr.io/devcontainers-extra/features/shellcheck:1": {}, + "ghcr.io/devcontainers-extra/features/yamllint:2": {}, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "DavidAnson.vscode-markdownlint", + "editorconfig.editorconfig", + "esbenp.prettier-vscode", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "redhat.vscode-yaml", + "timonwong.shellcheck", + "yzhang.markdown-all-in-one" + ] + } + }, + "postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template" } diff --git a/.editorconfig b/.editorconfig index da6e5f2ca..f816affbe 100644 --- a/.editorconfig +++ b/.editorconfig @@ -12,6 +12,21 @@ insert_final_newline = true trim_trailing_whitespace = true # BASH Files -[*.{.sh}] +[*.sh] indent_size = 4 indent_style = tab + +# JSON Files (Biome formatting) +[*.json] +indent_style = tab +indent_size = 2 + +# Steam appmanifest files (Valve ACF format) +[*.acf] +indent_style = tab +indent_size = 4 + +# Python +[*.py] +indent_style = space +indent_size = 4 diff --git a/.github/linters/.codespellrc b/.github/linters/.codespellrc new file mode 100644 index 000000000..229066881 --- /dev/null +++ b/.github/linters/.codespellrc @@ -0,0 +1,11 @@ +[codespell] +# Skip data tables that contain many short server identifiers (e.g. "fof", "nd") +skip = + lgsm/data/*.csv, + package-lock.json, + */package-lock.json, + node_modules, + */node_modules/* + +# Ignore common identifiers/acronyms and extensions used throughout LinuxGSM +ignore-words-list = distroname,fof,nd,sav,parms,ThirdParty diff --git a/.github/linters/.flake8 b/.github/linters/.flake8 new file mode 100644 index 000000000..6deafc261 --- /dev/null +++ b/.github/linters/.flake8 @@ -0,0 +1,2 @@ +[flake8] +max-line-length = 120 diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml new file mode 100644 index 000000000..094bbbcd6 --- /dev/null +++ b/.github/linters/.markdown-lint.yml @@ -0,0 +1,23 @@ +# Configuration for markdownlint (used by Super Linter) + +# MD041: README starts with HTML badges in this repo. +MD041: false + +# MD051: GitHub heading anchor generation can differ (emoji, punctuation). +MD051: false + +# MD013: The project documentation frequently contains long URLs/commands. +MD013: false + +# MD033: The main README uses inline HTML for badges. +MD033: false + +# Match existing list formatting in this repo. +MD007: + indent: 4 + +MD030: + ul_single: 3 + ol_single: 2 + ul_multi: 3 + ol_multi: 2 diff --git a/.github/linters/.shellcheckrc b/.github/linters/.shellcheckrc new file mode 100644 index 000000000..d16f69e0b --- /dev/null +++ b/.github/linters/.shellcheckrc @@ -0,0 +1 @@ +disable=SC2154,SC2034 diff --git a/.github/linters/.yaml-lint.yml b/.github/linters/.yaml-lint.yml new file mode 100644 index 000000000..c42932a49 --- /dev/null +++ b/.github/linters/.yaml-lint.yml @@ -0,0 +1,25 @@ +extends: default + +rules: + document-start: disable + truthy: disable + + line-length: + max: 200 + level: warning + allow-non-breakable-words: true + allow-non-breakable-inline-mappings: true + + braces: + min-spaces-inside: 0 + max-spaces-inside: 1 + min-spaces-inside-empty: 0 + max-spaces-inside-empty: 0 + + empty-lines: + max: 2 + max-start: 0 + max-end: 0 + + comments: + min-spaces-from-content: 1 diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 4e6d08327..9f6864e57 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -6,30 +6,30 @@ Fixes #[issue] ## Type of change -- [ ] Bug fix (a change which fixes an issue). -- [ ] New feature (a change which adds functionality). -- [ ] New Server (new server added). -- [ ] Refactor (restructures existing code). -- [ ] Comment update (typo, spelling, explanation, examples, etc). +- [ ] Bug fix (a change which fixes an issue). +- [ ] New feature (a change which adds functionality). +- [ ] New Server (new server added). +- [ ] Refactor (restructures existing code). +- [ ] Comment update (typo, spelling, explanation, examples, etc). ## Checklist PR will not be merged until all steps are complete. -- [ ] This pull request links to an issue. -- [ ] This pull request uses the `develop` branch as its base. -- [ ] This pull request subject follows the Conventional Commits standard. -- [ ] This code follows the style guidelines of this project. -- [ ] I have performed a self-review of my code. -- [ ] I have checked that this code is commented where required. -- [ ] I have provided a detailed enough description of this PR. -- [ ] I have checked if documentation needs updating. +- [ ] This pull request links to an issue. +- [ ] This pull request uses the `develop` branch as its base. +- [ ] This pull request subject follows the Conventional Commits standard. +- [ ] This code follows the style guidelines of this project. +- [ ] I have performed a self-review of my code. +- [ ] I have checked that this code is commented where required. +- [ ] I have provided a detailed enough description of this PR. +- [ ] I have checked if documentation needs updating. ## Documentation If documentation does need updating either update it by creating a PR (preferred) or request a documentation update. -- User docs: https://github.com/GameServerManagers/LinuxGSM-Docs -- Dev docs: https://github.com/GameServerManagers/LinuxGSM-Dev-Docs +- User docs: +- Dev docs: **Thank you for your Pull Request!** diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index 31b2fa949..de396dcd4 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -27,9 +27,10 @@ jobs: - name: Checkout code uses: actions/checkout@v6 with: - # super-linter needs the full git history to get the - # list of files that changed across commits - fetch-depth: 0 + # Shallow clone reduces transient fetch failures (HTTP 500) from GitHub. + # We lint the whole codebase instead of relying on git history. + fetch-depth: 1 + fetch-tags: false persist-credentials: false - name: Install Prettier plugins (for summary formatting) @@ -48,6 +49,7 @@ jobs: VALIDATE_JSON_PRETTIER: false VALIDATE_MARKDOWN_PRETTIER: false VALIDATE_NATURAL_LANGUAGE: false + VALIDATE_PYTHON_RUFF_FORMAT: false VALIDATE_SHELL_SHFMT: false VALIDATE_TRIVY: false VALIDATE_YAML_PRETTIER: false diff --git a/.github/workflows/add-to-project.yml b/.github/workflows/add-to-project.yml index e0b06990f..e96336264 100644 --- a/.github/workflows/add-to-project.yml +++ b/.github/workflows/add-to-project.yml @@ -5,6 +5,8 @@ on: - opened - labeled +permissions: {} + jobs: add-to-project: if: github.repository_owner == 'GameServerManagers' diff --git a/.github/workflows/details-check-generate-matrix.sh b/.github/workflows/details-check-generate-matrix.sh index bba9e8d5d..2c0803519 100755 --- a/.github/workflows/details-check-generate-matrix.sh +++ b/.github/workflows/details-check-generate-matrix.sh @@ -14,10 +14,12 @@ while read -r line; do export gamename distro=$(echo "$line" | awk -F, '{ print $4 }') export distro - echo -n "{" >> "shortnamearray.json" - echo -n "\"shortname\":" >> "shortnamearray.json" - echo -n "\"${shortname}\"" >> "shortnamearray.json" - echo -n "}," >> "shortnamearray.json" + { + echo -n "{"; + echo -n "\"shortname\":"; + echo -n "\"${shortname}\""; + echo -n "},"; + } >> "shortnamearray.json" done < <(tail -n +2 serverlist.csv) sed -i '$ s/.$//' "shortnamearray.json" echo -n "]" >> "shortnamearray.json" diff --git a/.github/workflows/details-check.yml b/.github/workflows/details-check.yml index f52d12c5a..c58aa0ae4 100644 --- a/.github/workflows/details-check.yml +++ b/.github/workflows/details-check.yml @@ -6,6 +6,9 @@ on: branches: - develop +permissions: + contents: read + concurrency: group: details-check-${{ github.ref_name }} cancel-in-progress: true @@ -28,7 +31,7 @@ jobs: run: | shortnamearray=$(cat shortnamearray.json) echo "${shortnamearray}" - echo -n "matrix=${shortnamearray}" >> $GITHUB_OUTPUT + echo -n "matrix=${shortnamearray}" >> "$GITHUB_OUTPUT" details-check: if: github.repository_owner == 'GameServerManagers' @@ -41,7 +44,7 @@ jobs: steps: - name: Download linuxgsm.sh - run: wget https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh; chmod +x linuxgsm.sh + run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh"; chmod +x linuxgsm.sh - name: Install dependencies run: sudo apt-get install libxml2-utils jq diff --git a/.github/workflows/git-sync.yml b/.github/workflows/git-sync.yml index 544ba6892..42c660d9b 100644 --- a/.github/workflows/git-sync.yml +++ b/.github/workflows/git-sync.yml @@ -7,6 +7,8 @@ on: - master - develop +permissions: {} + jobs: gitHub-to-bitbucket: if: github.repository_owner == 'GameServerManagers' diff --git a/.github/workflows/potential-duplicates.yml b/.github/workflows/potential-duplicates.yml index ea0ba23fd..39a3189d8 100644 --- a/.github/workflows/potential-duplicates.yml +++ b/.github/workflows/potential-duplicates.yml @@ -3,6 +3,10 @@ on: issues: types: - opened + +permissions: + issues: write + jobs: potential-duplicates: if: github.repository_owner == 'GameServerManagers' diff --git a/.github/workflows/serverlist-validate-game-icons.sh b/.github/workflows/serverlist-validate-game-icons.sh index 2fdb0ff8f..b3ba7e418 100755 --- a/.github/workflows/serverlist-validate-game-icons.sh +++ b/.github/workflows/serverlist-validate-game-icons.sh @@ -2,6 +2,8 @@ cd "${datadir}" || exit +exitcode=0 + echo "" echo "Checking that all the game servers listed in serverlist.csv have a shortname-icon.png file" for shortname in $(tail -n +2 serverlist.csv | cut -d ',' -f1); do @@ -16,9 +18,11 @@ done echo "" echo "Checking if an unexpected gameicon exists" -for gameicon in $(ls -1 gameicons); do +shopt -s nullglob +for gameiconpath in gameicons/*; do + gameicon="$(basename "${gameiconpath}")" # check if $gameicon is in serverlist.csv - if ! grep -q "${gameicon%-icon.png}" serverlist.csv; then + if ! grep -q -F "${gameicon%-icon.png}" serverlist.csv; then echo "ERROR: gameicon ${gameicon} is not in serverlist.csv" exitcode=1 else @@ -28,7 +32,7 @@ done echo "" echo "Checking that the number of gameicons matches the number of servers in serverlist.csv" -gameiconcount="$(ls -1 gameicons | wc -l)" +gameiconcount="$(find gameicons -mindepth 1 -maxdepth 1 -type f | wc -l)" serverlistcount="$(tail -n +2 serverlist.csv | wc -l)" if [ "${gameiconcount}" -ne "${serverlistcount}" ]; then echo "ERROR: game icons (${gameiconcount}) does not match serverlist.csv ($serverlistcount)" @@ -37,4 +41,4 @@ else echo "OK: gameiconcount ($gameiconcount) matches serverlistcount ($serverlistcount)" fi -exit ${exitcode} +exit "${exitcode}" diff --git a/.github/workflows/serverlist-validate.sh b/.github/workflows/serverlist-validate.sh index 7d931372d..3d83d89da 100755 --- a/.github/workflows/serverlist-validate.sh +++ b/.github/workflows/serverlist-validate.sh @@ -3,12 +3,15 @@ echo "Checking that all the game servers are listed in all csv files" echo "this check will ensure serverlist.csv has the same number of lines (-2 lines) as the other csv files" # count the number of lines in the serverlist.csv cd "${datadir}" || exit + +exitcode=0 serverlistcount="$(tail -n +2 serverlist.csv | wc -l)" echo "serverlistcount: $serverlistcount" # get list of all csv files starting with ubunutu debian centos -csvlist="$(ls -1 | grep -E '^(ubuntu|debian|centos|rhel|almalinux|rocky).*\.csv$')" +shopt -s nullglob +csvlist=(ubuntu*.csv debian*.csv centos*.csv rhel*.csv almalinux*.csv rocky*.csv) # loop though each csv file and make sure the number of lines is the same as the serverlistcount -for csv in $csvlist; do +for csv in "${csvlist[@]}"; do csvcount="$(wc -l < "${csv}")" csvcount=$((csvcount - 2)) if [ "$csvcount" -ne "$serverlistcount" ]; then @@ -35,4 +38,4 @@ for shortname in $(tail -n +2 serverlist.csv | cut -d ',' -f1); do fi done -exit ${exitcode} +exit "${exitcode}" diff --git a/.github/workflows/serverlist-validate.yml b/.github/workflows/serverlist-validate.yml index f4a95a039..c2605b062 100644 --- a/.github/workflows/serverlist-validate.yml +++ b/.github/workflows/serverlist-validate.yml @@ -3,6 +3,9 @@ on: workflow_dispatch: push: +permissions: + contents: read + jobs: serverlist-validate: if: github.repository_owner == 'GameServerManagers' diff --git a/.github/workflows/trigger-docker-build.yml b/.github/workflows/trigger-docker-build.yml index ab37c882d..390123322 100644 --- a/.github/workflows/trigger-docker-build.yml +++ b/.github/workflows/trigger-docker-build.yml @@ -6,6 +6,8 @@ on: types: - published +permissions: {} + jobs: trigger_build_docker-linuxgsm: if: github.repository_owner == 'GameServerManagers' diff --git a/.github/workflows/update-check.yml b/.github/workflows/update-check.yml index 2f2f7babc..8863cedc7 100644 --- a/.github/workflows/update-check.yml +++ b/.github/workflows/update-check.yml @@ -6,6 +6,8 @@ on: branches: - develop +permissions: {} + concurrency: group: update-check-${{ github.ref_name }} cancel-in-progress: true @@ -22,7 +24,7 @@ jobs: steps: - name: Download linuxgsm.sh - run: wget https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh; chmod +x linuxgsm.sh + run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh"; chmod +x linuxgsm.sh - name: Install dependencies run: sudo dpkg --add-architecture i386; sudo apt-get update; diff --git a/.github/workflows/update-copyright-years-in-license-file.yml b/.github/workflows/update-copyright-years-in-license-file.yml index 3301c9cb7..1123b8cce 100644 --- a/.github/workflows/update-copyright-years-in-license-file.yml +++ b/.github/workflows/update-copyright-years-in-license-file.yml @@ -4,6 +4,10 @@ on: schedule: - cron: "0 3 1 1 *" # 03:00 AM on January 1 +permissions: + contents: write + pull-requests: write + jobs: update-license-year: if: github.repository_owner == 'GameServerManagers' diff --git a/.github/workflows/version-check.sh b/.github/workflows/version-check.sh old mode 100644 new mode 100755 diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..7b065e422 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,3 @@ +# Prettier auto-commit runs with GITHUB_TOKEN (GitHub App). +# GitHub blocks that token from creating/updating anything under .github/workflows. +.github/workflows/** diff --git a/.prettierrc b/.prettierrc index 1902f8021..02d542d50 100644 --- a/.prettierrc +++ b/.prettierrc @@ -1,3 +1,3 @@ { - "plugins": ["prettier-plugin-sh"] + "plugins": ["prettier-plugin-sh"] } diff --git a/.prettierrc.json b/.prettierrc.json index 02d542d50..1902f8021 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,3 +1,3 @@ { - "plugins": ["prettier-plugin-sh"] + "plugins": ["prettier-plugin-sh"] } diff --git a/.shellcheckrc b/.shellcheckrc index 026ee646c..d16f69e0b 100644 --- a/.shellcheckrc +++ b/.shellcheckrc @@ -1 +1 @@ -disable=SC2154 +disable=SC2154,SC2034 diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d31b65dd2..5c06a83bf 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,12 +1,12 @@ { - "recommendations": [ - "DavidAnson.vscode-markdownlint", - "editorconfig.editorconfig", - "esbenp.prettier-vscode", - "github.vscode-github-actions", - "GitHub.vscode-pull-request-github", - "redhat.vscode-yaml", - "timonwong.shellcheck", - "yzhang.markdown-all-in-one" - ] + "recommendations": [ + "DavidAnson.vscode-markdownlint", + "editorconfig.editorconfig", + "esbenp.prettier-vscode", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "redhat.vscode-yaml", + "timonwong.shellcheck", + "yzhang.markdown-all-in-one" + ] } diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index a69325281..fb935a066 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -17,24 +17,24 @@ diverse, inclusive, and healthy community. Examples of behavior that contributes to a positive environment for our community include: -- Demonstrating empathy and kindness toward other people -- Being respectful of differing opinions, viewpoints, and experiences -- Giving and gracefully accepting constructive feedback -- Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -- Focusing on what is best not just for us as individuals, but for the - overall community +- Demonstrating empathy and kindness toward other people +- Being respectful of differing opinions, viewpoints, and experiences +- Giving and gracefully accepting constructive feedback +- Accepting responsibility and apologizing to those affected by our mistakes, + and learning from the experience +- Focusing on what is best not just for us as individuals, but for the + overall community Examples of unacceptable behavior include: -- The use of sexualized language or imagery, and sexual attention or - advances of any kind -- Trolling, insulting or derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or email - address, without their explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery, and sexual attention or + advances of any kind +- Trolling, insulting or derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or email + address, without their explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Enforcement Responsibilities diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 7b549c795..ab17437f6 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,31 +8,31 @@ The following is a set of guidelines for contributing to LinuxGSM, which are hos [Contributing to LinuxGSM](#contributing-to-linuxgsm) -- [Table of Contents](#table-of-contents) -- [Code of Conduct](#code-of-conduct) -- [๐ŸŽ‰ Bug/Enhancement Contributions ๐Ÿ›](#bug-enhancement-contributions) - - [๐Ÿ›Reporting Bugs](#reporting-bugs) - - [Before Submitting A Bug Report](#before-submitting-a-bug-report) - - [How Do I Submit A (Good) Bug Report?](#how-do-i-submit-a--good--bug-report-) - - [๐ŸŽ‰Suggesting Features](#suggesting-features) - - [Before Submitting An Feature Suggestion](#before-submitting-an-feature-suggestion) - - [How Do I Submit A (Good) Feature Suggestion?](#how-do-i-submit-a--good--feature-suggestion-) - - [๐ŸŽฎ Game Server Requests](#game-server-requests) - - [Before Submitting a Game Server Request](#before-submitting-a-game-server-request) - - [How Do I Submit A (Good) Game Server Request?](#how-do-i-submit-a--good--game-server-request-) - - [๐ŸŽฎ Game Server Specific Issues](#game-server-specific-issues) -- [๐Ÿ’ป Code Contributions](#code-contributions) - - [Pull Requests](#pull-requests) - - [Pull Request naming convention](#pull-request-naming-convention) - - [Testing](#testing) - - [Pull Request Status Checks](#pull-request-status-checks) - - [Test Environment](#test-environment) - - [:wine_glass: Styleguides](#-wine-glass--styleguides) - - [Git Commit Messages](#git-commit-messages) - - [BASH Styleguide](#bash-styleguide) -- [:blue_book: Document Contributions](#-blue-book--document-contributions) - - [Documentation Styleguide](#documentation-styleguide) -- [Issue and Pull Request Labels](#issue-and-pull-request-labels) +- [Table of Contents](#table-of-contents) +- [Code of Conduct](#code-of-conduct) +- [๐ŸŽ‰ Bug/Enhancement Contributions ๐Ÿ›](#bug-enhancement-contributions) + - [๐Ÿ›Reporting Bugs](#reporting-bugs) + - [Before Submitting A Bug Report](#before-submitting-a-bug-report) + - [How Do I Submit A (Good) Bug Report?](#how-do-i-submit-a--good--bug-report-) + - [๐ŸŽ‰Suggesting Features](#suggesting-features) + - [Before Submitting An Feature Suggestion](#before-submitting-an-feature-suggestion) + - [How Do I Submit A (Good) Feature Suggestion?](#how-do-i-submit-a--good--feature-suggestion-) + - [๐ŸŽฎ Game Server Requests](#game-server-requests) + - [Before Submitting a Game Server Request](#before-submitting-a-game-server-request) + - [How Do I Submit A (Good) Game Server Request?](#how-do-i-submit-a--good--game-server-request-) + - [๐ŸŽฎ Game Server Specific Issues](#game-server-specific-issues) +- [๐Ÿ’ป Code Contributions](#code-contributions) + - [Pull Requests](#pull-requests) + - [Pull Request naming convention](#pull-request-naming-convention) + - [Testing](#testing) + - [Pull Request Status Checks](#pull-request-status-checks) + - [Test Environment](#test-environment) + - [:wine_glass: Styleguides](#-wine-glass--styleguides) + - [Git Commit Messages](#git-commit-messages) + - [BASH Styleguide](#bash-styleguide) +- [:blue_book: Document Contributions](#-blue-book--document-contributions) + - [Documentation Styleguide](#documentation-styleguide) +- [Issue and Pull Request Labels](#issue-and-pull-request-labels) ## Code of Conduct @@ -48,20 +48,20 @@ Before creating bug reports, please check [this list](https://github.com/GameSer #### Before Submitting A Bug Report -- **Check the [documentation](https://docs.linuxgsm.com).** You might be able to find the cause of the problem and fix things yourself. -- **Check the** [**support page**](https://linuxgsm.com/support) for links to other support options. -- **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one. +- **Check the [documentation](https://docs.linuxgsm.com).** You might be able to find the cause of the problem and fix things yourself. +- **Check the** [**support page**](https://linuxgsm.com/support) for links to other support options. +- **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the problem has already been reported. If it has **and the issue is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one. #### How Do I Submit A (Good) Bug Report? Bugs are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue and provide the following information by filling in [the issues form](https://github.com/GameServerManagers/LinuxGSM/issues/new/choose). -- **Use a clear and descriptive title** for the issue to identify the problem. -- **Complete the user story** to give a summary of the issue. -- **Provide basic info** to help us understand the context of the issue. -- **Provide further info** to give specifics and more detail. -- **Give steps to reproduce** the issue, allowing developers to follow steps that lead to the issue. -- **Explain what you expect** to happen, so we know what you think should occur. +- **Use a clear and descriptive title** for the issue to identify the problem. +- **Complete the user story** to give a summary of the issue. +- **Provide basic info** to help us understand the context of the issue. +- **Provide further info** to give specifics and more detail. +- **Give steps to reproduce** the issue, allowing developers to follow steps that lead to the issue. +- **Explain what you expect** to happen, so we know what you think should occur. ### ๐ŸŽ‰Suggesting Features @@ -69,19 +69,19 @@ This section guides you through submitting a feature suggestion for LinuxGSM, in #### Before Submitting An Feature Suggestion -- **Check the** [**documentation**]() to confirm that the enhancement doesnโ€™t already exist. -- **Check your** [**LinuxGSM version**](https://docs.linuxgsm.com/commands/update-lgsm)**.** A newer version of LinuxGSM may already have your enhancement. -- **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the enhancement has already been suggested. If it has **and the enhancement is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one. +- **Check the** [**documentation**]() to confirm that the enhancement doesnโ€™t already exist. +- **Check your** [**LinuxGSM version**](https://docs.linuxgsm.com/commands/update-lgsm)**.** A newer version of LinuxGSM may already have your enhancement. +- **Perform a** [**cursory search**](https://github.com/search?q=org:GameServerManagers%20type:issues&type=Issues) to see if the enhancement has already been suggested. If it has **and the enhancement is still open**, add a comment to the existing issue and give it a thumbs up instead of opening a new one. #### How Do I Submit A (Good) Feature Suggestion? Features are tracked as [GitHub issues](https://guides.github.com/features/issues/). Create an issue and provide the following information by filling in [the issues form](https://github.com/GameServerManagers/LinuxGSM/issues/new/choose). -- **Use a clear and descriptive title** for the issue to identify the problem. -- **Complete the user story** to give a summary of the issue. -- **Provide basic info** to help us understand the context of the enhancement. -- **Provide further info** to give specifics and more detail. -- **Provide any further reading** materials that might assist in developing the enhancement. +- **Use a clear and descriptive title** for the issue to identify the problem. +- **Complete the user story** to give a summary of the issue. +- **Provide basic info** to help us understand the context of the enhancement. +- **Provide further info** to give specifics and more detail. +- **Provide any further reading** materials that might assist in developing the enhancement. ### ๐ŸŽฎ Game Server Requests @@ -89,14 +89,14 @@ This section guides you through submitting a game server request for LinuxGSM, F #### Before Submitting a Game Server Request -- **Check for existing** [**game server requests**](https://github.com/GameServerManagers/LinuxGSM/labels/type%3A%20game%20server%20request) to see if the new game server has already been suggested. If it has **and if the new game server is still open**, give it a thumbs up. -- **Check the game server is supported on Linux**, this does not include Wine servers which we do not support. +- **Check for existing** [**game server requests**](https://github.com/GameServerManagers/LinuxGSM/labels/type%3A%20game%20server%20request) to see if the new game server has already been suggested. If it has **and if the new game server is still open**, give it a thumbs up. +- **Check the game server is supported on Linux**, this does not include Wine servers which we do not support. #### How Do I Submit A (Good) Game Server Request? -- The title should be as follows: **[Server Request] Game Name** -- **Provide Steam App ID** if applicable -- **Supply any documentation/how-to guides** for the game server. +- The title should be as follows: **[Server Request] Game Name** +- **Provide Steam App ID** if applicable +- **Supply any documentation/how-to guides** for the game server. ### ๐ŸŽฎ Game Server Specific Issues @@ -114,10 +114,10 @@ A [list](https://docs.linuxgsm.com/support/game-server) of known game developer The process described here has several goals: -- Maintain LinuxGSM quality. -- Fix problems that are important to users. -- Engage the community in working toward the best possible LinuxGSM. -- Enable a sustainable system for LinuxGSM maintainers to review contributions. +- Maintain LinuxGSM quality. +- Fix problems that are important to users. +- Engage the community in working toward the best possible LinuxGSM. +- Enable a sustainable system for LinuxGSM maintainers to review contributions. Please follow these steps to have your contribution considered by the maintainers: @@ -139,24 +139,23 @@ If applied, this commit will _your subject line here_ For example: -- If applied, this commit will **refactor subsystem X for readability** -- If applied, this commit will **update getting started documentation** -- If applied, this commit will **remove deprecated methods** -- If applied, this commit will **release version 1.0.0** -- If applied, this commit will **merge pull request #123 from user/branch** +- If applied, this commit will **refactor subsystem X for readability** +- If applied, this commit will **update getting started documentation** +- If applied, this commit will **remove deprecated methods** +- If applied, this commit will **release version 1.0.0** +- If applied, this commit will **merge pull request #123 from user/branch** Notice how this doesnโ€™t work for the other non-imperative forms: -- If applied, this commit will **fixed bug with Y** -- If applied, this commit will **change the behaviour of X** -- If applied, this commit will **more fixes for broken stuff** -- If applied, this commit will **sweet new API methods** +- If applied, this commit will **fixed bug with Y** +- If applied, this commit will **change the behaviour of X** +- If applied, this commit will **more fixes for broken stuff** +- If applied, this commit will **sweet new API methods** Below is an example of the subject line for a pull request: -**feat(alerts): add slack support to alerts** - -**fix(csgoserver): remove SteamCMD auth requirement 32-bit workaround** +- feat(alerts): add slack support to alerts +- fix(csgoserver): remove SteamCMD auth requirement 32-bit workaround ### Testing @@ -211,10 +210,10 @@ Labels to help pinpoint what the issue or PR relates to. variants: -- _distro_ -- _engine_ -- _game_ -- _info_ +- _distro_ +- _engine_ +- _game_ +- _info_ **outcome** Labels Labels that identify why an issue was closed. diff --git a/README.md b/README.md index 4075a4e3d..ad8847133 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,10 @@

- LinuxGSM - Codacy grade - GitHub Workflow Status - Discord - SteamCMD - MIT License + LinuxGSM + Codacy grade + GitHub Workflow Status + Discord + SteamCMD + MIT License

[LinuxGSM](https://linuxgsm.com) is the command-line tool for quick, simple deployment and management of Linux dedicated game servers. @@ -17,21 +17,21 @@ Traditionally game servers are not easy to manage yourself. Admins often have to 100+ game servers supported -- :truck: Installer -- :mag: Monitor -- :phone: Alerts -- :cloud: Updater -- :blue_book: Server Details -- :floppy_disk: Backup -- :computer: Console +- :truck: Installer +- :mag: Monitor +- :phone: Alerts +- :cloud: Updater +- :blue_book: Server Details +- :floppy_disk: Backup +- :computer: Console ## :penguin: Compatibility LinuxGSM will run on popular distros as long as the minimum requirements are met. -- Ubuntu -- Debian -- CentOS +- Ubuntu +- Debian +- CentOS Other distros are likely to work but are not fully tested. diff --git a/lgsm/config-default/config-lgsm/armarserver/_default.cfg b/lgsm/config-default/config-lgsm/armarserver/_default.cfg index d5b6d0e18..e7e8c24f4 100644 --- a/lgsm/config-default/config-lgsm/armarserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/armarserver/_default.cfg @@ -9,7 +9,7 @@ #### Game Server Settings #### # https://community.bistudio.com/wiki/Arma_Reforger:Server_Hosting -# MaxFPS to limit the used Server resouces +# MaxFPS to limit the used Server resources maxfps="60" # Profile Name diff --git a/lgsm/config-default/config-lgsm/necserver/_default.cfg b/lgsm/config-default/config-lgsm/necserver/_default.cfg index 6c1f65a39..648e0a40c 100644 --- a/lgsm/config-default/config-lgsm/necserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/necserver/_default.cfg @@ -8,7 +8,7 @@ #### Game Server Settings #### -## Pre-defined Paramters | https://docs.linuxgsm.com/configuration/start-parameters#predefined-parameters +## Pre-defined Parameters | https://docs.linuxgsm.com/configuration/start-parameters#predefined-parameters worldname="MyWorld" ## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters diff --git a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg index 7f4aeb9bc..565187394 100644 --- a/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2cserver/_default.cfg @@ -19,7 +19,7 @@ httppassword="CHANGE_ME" httpport="8080" mods="" serverpassword="" -# Add the following line to the parms if you want a private server. Ensuring +# Add the following line to the params if you want a private server. Ensuring # that the password variable above is not left empty. # -password \"${serverpassword}\" diff --git a/lgsm/config-default/config-lgsm/ns2server/_default.cfg b/lgsm/config-default/config-lgsm/ns2server/_default.cfg index 69aa2486a..8964f1dfd 100644 --- a/lgsm/config-default/config-lgsm/ns2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/ns2server/_default.cfg @@ -20,7 +20,7 @@ httppassword="CHANGE_ME" httpport="8080" modserverport="27031" serverpassword="" -# Add the following line to the parms if you want a private server. Ensuring +# Add the following line to the params if you want a private server. Ensuring # that the password variable above is not left empty. # -password '${serverpassword}' diff --git a/lgsm/config-default/config-lgsm/pwserver/_default.cfg b/lgsm/config-default/config-lgsm/pwserver/_default.cfg index 7359064a0..c9052958a 100644 --- a/lgsm/config-default/config-lgsm/pwserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/pwserver/_default.cfg @@ -11,7 +11,7 @@ ## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters servername="LinuxGSM" -# For community servers (serverlist) you need to change these settings (publicip & publicport) in the gameserver config file aswell +# For community servers (serverlist) you need to change these settings (publicip & publicport) in the gameserver config file as well port="8211" steamport="27015" diff --git a/lgsm/data/name-left.csv b/lgsm/data/name-left.csv index 9a47b4baf..2a95f7106 100644 --- a/lgsm/data/name-left.csv +++ b/lgsm/data/name-left.csv @@ -105,4 +105,4 @@ wonderful xenodochial youthful zealous -zen \ No newline at end of file +zen diff --git a/lgsm/data/name-right.csv b/lgsm/data/name-right.csv index 8e04d85b4..3fdbb9278 100644 --- a/lgsm/data/name-right.csv +++ b/lgsm/data/name-right.csv @@ -234,4 +234,4 @@ wright wu yalow yonath -zhukovsky \ No newline at end of file +zhukovsky diff --git a/lgsm/modules/README.md b/lgsm/modules/README.md index de008ecfa..a0aee384c 100644 --- a/lgsm/modules/README.md +++ b/lgsm/modules/README.md @@ -6,12 +6,12 @@ These modules are scripts that are called upon by the primary script linuxgsm.sh Modules have been named to give an idea of what the function does. -- core: Essential modules that will always run first. -- command: Primary command function. -- check: Runs checks that will either halt on or fix an issue. -- dev: development modules. -- fix: Applies a game server specific fix. -- info: retrieves information from a source such as config file or the OS. -- install: modules related to the installer. -- monitor: modules related to monitor. -- update: modules that update the game server. +- core: Essential modules that will always run first. +- command: Primary command function. +- check: Runs checks that will either halt on or fix an issue. +- dev: development modules. +- fix: Applies a game server specific fix. +- info: retrieves information from a source such as config file or the OS. +- install: modules related to the installer. +- monitor: modules related to monitor. +- update: modules that update the game server. diff --git a/lgsm/modules/alert.sh b/lgsm/modules/alert.sh old mode 100644 new mode 100755 index 16ba7e939..ac7d92d83 --- a/lgsm/modules/alert.sh +++ b/lgsm/modules/alert.sh @@ -10,13 +10,9 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" # Generates alert log of the details at the time of the alert. # Used with email alerts. fn_alert_log() { - info_distro.sh - info_game.sh - info_messages.sh if [ -f "${alertlog}" ]; then rm -f "${alertlog:?}" fi - { fn_info_messages_head fn_info_messages_distro @@ -24,7 +20,7 @@ fn_alert_log() { fn_info_messages_gameserver_resource fn_info_messages_gameserver fn_info_logs - } | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | tee -a "${alertlog}" >/dev/null 2>&1 + } | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[m|K]//g" | tee -a "${alertlog}" > /dev/null 2>&1 } fn_alert_test() { @@ -97,45 +93,66 @@ fn_alert_monitor_query() { # Update alerts fn_alert_update() { - fn_script_log_info "Sending alert: ${selfname} has received a game server update: ${localbuild}" + # If previousbuild is set show transition, else fallback to single version. + if [ -n "${previousbuild:-}" ] && [ -n "${localbuild:-}" ]; then + fn_script_log_info "Sending alert: ${selfname} updated: ${previousbuild} -> ${localbuild}" + alertmessage="${selfname} updated: ${previousbuild} -> ${localbuild}." + else + fn_script_log_info "Sending alert: ${selfname} updated to ${localbuild}" + alertmessage="${selfname} updated to ${localbuild}." + fi alertaction="Updated" alertemoji="๐ŸŽ‰" alertsound="1" - alertmessage="${selfname} has received a game server update: ${localbuild}." # Green alertcolourhex="#00cd00" alertcolourdec="52480" } -fn_alert_update_request() { - fn_script_log_info "Sending alert: ${selfname} has requested an update and needs to be restarted." - alertaction="Updating" +# Update failure alert +fn_alert_update_failed() { + # Expect updatefailureexpected (target version) and updatefailuregot (actual localbuild) if set + local updateexpected="${updatefailureexpected:-${remotebuild:-unknown}}" + local updategot="${updatefailuregot:-${localbuild:-unknown}}" + fn_script_log_error "Sending alert: ${selfname} update failed: expected ${updateexpected}, got ${updategot}" + alertaction="Update Failed" + alertemoji="โŒ" + alertsound="2" + alertmessage="${selfname} update failed: expected ${updateexpected}, got ${updategot}. Manual intervention required." + # Red + alertcolourhex="#cd0000" + alertcolourdec="13434880" +} + +fn_alert_update_restart_request() { + fn_script_log_info "Sending alert: ${selfname} restart requested" + alertaction="Restart Requested" alertemoji="๐ŸŽ‰" alertsound="1" - alertmessage="${selfname} has requested an update and needs to be restarted." + alertmessage="${selfname} has requested a restart for an update to be applied. Restarting now." # Blue alertcolourhex="#1e90ff" alertcolourdec="2003199" } fn_alert_check_update() { - fn_script_log_info "Sending alert: ${gamename} update available: ${remotebuildversion}" - alertaction="Update available" + fn_script_log_info "Sending alert: ${gamename} update available: ${localbuild} -> ${remotebuild}" + alertaction="Update Available" alertemoji="๐ŸŽ‰" alertsound="1" - alertmessage="${gamename} update available: ${remotebuildversion}" + alertmessage="${gamename} update available: ${localbuild} -> ${remotebuild}" # Blue alertcolourhex="#1e90ff" alertcolourdec="2003199" } fn_alert_update_linuxgsm() { - fn_script_log_info "Sending alert: ${selfname} has received an LinuxGSM update" + fn_script_log_info "Sending alert: ${selfname} has received a LinuxGSM update" alertaction="Updated" alertemoji="๐ŸŽ‰" alertsound="1" alertbody="${gamename} update available" - alertmessage="${selfname} has received an LinuxGSM update and been restarted." + alertmessage="${selfname} has received a LinuxGSM update and been restarted." # Green alertcolourhex="#00cd00" alertcolourdec="52480" @@ -197,8 +214,9 @@ fn_alert_info() { alertcolourdec="2003199" } -# Images -alerticon="https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/gameicons/${shortname}-icon.png" +info_distro.sh +info_game.sh +info_messages.sh if [ "${alert}" == "permissions" ]; then fn_alert_permissions @@ -210,8 +228,10 @@ elif [ "${alert}" == "test" ]; then fn_alert_test elif [ "${alert}" == "update" ]; then fn_alert_update -elif [ "${alert}" == "update-request" ]; then - fn_alert_update_request +elif [ "${alert}" == "update-failed" ]; then + fn_alert_update_failed +elif [ "${alert}" == "update-restart-request" ]; then + fn_alert_update_restart_request elif [ "${alert}" == "check-update" ]; then fn_alert_check_update elif [ "${alert}" == "config" ]; then @@ -237,6 +257,7 @@ else fi alerttitle="${alertemoji} ${alertaction} - ${servername} ${alertemoji}" +alerticon="https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/gameicons/${shortname}-icon.png" # Generate alert log. fn_alert_log diff --git a/lgsm/modules/alert_discord.sh b/lgsm/modules/alert_discord.sh old mode 100644 new mode 100755 index 1440b6a96..e4bf6307f --- a/lgsm/modules/alert_discord.sh +++ b/lgsm/modules/alert_discord.sh @@ -43,39 +43,38 @@ json=$( "inline": true }, { - "name": "Server Time", - "value": "$(date)", + "name": "Server IP", + "value": "\`${alertip}:${port}\`", "inline": true }, { - "name": "More info", - "value": "${alerturl}", + "name": "Server Time", + "value": "$(date)", "inline": true } EOF ) -if [ -n "${querytype}" ]; then +if [ -n "${alerturl}" ]; then json+=$( cat << EOF , { - "name": "Is my Game Server Online?", - "value": "https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}", + "name": "More info", + "value": "${alerturl}", "inline": true } EOF ) fi -if [ -n "${alerturl}" ]; then +if [ -n "${querytype}" ]; then json+=$( cat << EOF , { - "name": "More info", - "value": "${alerturl}", - "inline": true + "name": "Is my Game Server Online?", + "value": "https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}" } EOF ) diff --git a/lgsm/modules/alert_email.sh b/lgsm/modules/alert_email.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/alert_gotify.sh b/lgsm/modules/alert_gotify.sh old mode 100644 new mode 100755 index 2f627c774..647445746 --- a/lgsm/modules/alert_gotify.sh +++ b/lgsm/modules/alert_gotify.sh @@ -11,7 +11,7 @@ json=$( cat << EOF { "title": "${alerttitle}", - "message": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\nHostname\n${HOSTNAME}\n\n + "message": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\n EOF ) diff --git a/lgsm/modules/alert_ifttt.sh b/lgsm/modules/alert_ifttt.sh old mode 100644 new mode 100755 index aaae3b4e8..59bb8d965 --- a/lgsm/modules/alert_ifttt.sh +++ b/lgsm/modules/alert_ifttt.sh @@ -12,7 +12,7 @@ json=$( { "value1": "${selfname}", "value2": "${alerttitle}", - "value3": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\nHostname\n${HOSTNAME}\n\n + "value3": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\n EOF ) diff --git a/lgsm/modules/alert_ntfy.sh b/lgsm/modules/alert_ntfy.sh old mode 100644 new mode 100755 index 35e3f4c55..3f9b0159e --- a/lgsm/modules/alert_ntfy.sh +++ b/lgsm/modules/alert_ntfy.sh @@ -35,23 +35,31 @@ else tags="${alertemoji}" fi -# Construct the message body -message="Server Name: ${servername} -Information: ${alertmessage} -Game: ${gamename} -Server IP: ${alertip}:${port} -Hostname: ${HOSTNAME} -Server Time: $(date)" +# Construct the message body (keep formatting consistent with other plain-text alerts) +message="Server Name +${servername} + +Information +${alertmessage} + +Game +${gamename} + +Server IP +${alertip}:${port} + +Server Time +$(date)" # Add optional links if available if [ -n "${querytype}" ]; then - message+="\nIs my Game Server Online?: https://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}" + message+="\n\nIs my Game Server Online?\nhttps://ismygameserver.online/${imgsoquerytype}/${alertip}:${queryport}" fi # Use alerturl for the click action if available clickurl="" if [ -n "${alerturl}" ]; then - message+="\nMore info: ${alerturl}" + message+="\n\nMore info\n${alerturl}" clickurl="${alerturl}" fi diff --git a/lgsm/modules/alert_pushbullet.sh b/lgsm/modules/alert_pushbullet.sh old mode 100644 new mode 100755 index abdfa0bb2..62937b3a7 --- a/lgsm/modules/alert_pushbullet.sh +++ b/lgsm/modules/alert_pushbullet.sh @@ -13,7 +13,7 @@ json=$( "channel_tag": "${channeltag}", "type": "note", "title": "${alerttitle}", - "body": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\nHostname\n${HOSTNAME}\n\n + "body": "Server Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\n EOF ) diff --git a/lgsm/modules/alert_pushover.sh b/lgsm/modules/alert_pushover.sh old mode 100644 new mode 100755 index 8dc0ce2dc..3437ba83e --- a/lgsm/modules/alert_pushover.sh +++ b/lgsm/modules/alert_pushover.sh @@ -22,7 +22,7 @@ else alertpriority="0" fi -message=" Server name
${servername}

Information
${alertmessage}

Game
${gamename}

Server IP
${alertip}:${port}

Hostname
${HOSTNAME}

" +message=" Server Name
${servername}

Information
${alertmessage}

Game
${gamename}

Server IP
${alertip}:${port}

" if [ -n "${querytype}" ]; then message+="Is my Game Server Online?
Check here

" @@ -32,7 +32,7 @@ if [ -n "${alerturl}" ]; then message+="More info
${alerturl}

" fi -message+="Server Time
$(date)" +message+="Server Time
$(date)" pushoversend=$(curl --connect-timeout 3 -sS \ -F token="${pushovertoken}" \ diff --git a/lgsm/modules/alert_rocketchat.sh b/lgsm/modules/alert_rocketchat.sh old mode 100644 new mode 100755 index 35bcf4928..68045221e --- a/lgsm/modules/alert_rocketchat.sh +++ b/lgsm/modules/alert_rocketchat.sh @@ -40,38 +40,20 @@ json=$( { "short": false, "title": "Server IP", - "value": "${alertip}:${port}" - }, - { - "short": false, - "title": "Hostname", - "value": "${HOSTNAME}" - }, - { - "short": false, - "title": "More info", - "value": "${alerturl}" - }, - { - "short": false, - "title": "Server Time", - "value": "$(date)" + "value": "\`${alertip}:${port}\`" } - ] - } - ] -} EOF ) if [ -n "${querytype}" ]; then json+=$( cat << EOF + , { "short": false, "title": "Is my Game Server Online?", "value": "" - }, + } EOF ) fi @@ -79,55 +61,19 @@ fi if [ -n "${alerturl}" ]; then json+=$( cat << EOF + , { "short": false, "title": "More info", "value": "${alerturl}" - }, + } EOF ) fi json+=$( cat << EOF -{ - "alias": "LinuxGSM", - "text": "*${alerttitle}*", - "attachments": [ - { - "title": "", - "color": "${alertcolourhex}", - "author_name": "LinuxGSM Alert", - "author_link": "https://linuxgsm.com", - "author_icon": "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/alert_discord_logo.jpg", - "thumb_url": "${alerticon}", - "text": "", - "fields": [ - { - "short": false, - "title": "Server Name", - "value": "${servername}" - }, - { - "short": false, - "title": "Information", - "value": "${alertmessage}" - }, - { - "short": false, - "title": "Game", - "value": "${gamename}" - }, - { - "short": false, - "title": "Server IP", - "value": "${alertip}:${port}" - }, - { - "short": false, - "title": "Hostname", - "value": "${HOSTNAME}" - }, + , { "short": false, "title": "Server Time", diff --git a/lgsm/modules/alert_slack.sh b/lgsm/modules/alert_slack.sh old mode 100644 new mode 100755 index 0a1e9015e..defb1f77f --- a/lgsm/modules/alert_slack.sh +++ b/lgsm/modules/alert_slack.sh @@ -50,10 +50,6 @@ json=$( "type": "mrkdwn", "text": "*Server IP*\n\`${alertip}:${port}\`" }, - { - "type": "mrkdwn", - "text": "*Hostname*\n${HOSTNAME}" - }, { "type": "mrkdwn", "text": "*Server Time*\n$(date)" @@ -62,41 +58,22 @@ json=$( "accessory": { "type": "image", "image_url": "${alerticon}", - "alt_text": "cute cat" + "alt_text": "LinuxGSM game icon" } - }, - { - "type": "context", - "elements": [ - { - "type": "image", - "image_url": "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/alert_discord_logo.jpg", - "alt_text": "LinuxGSM icon" - }, - { - "type": "plain_text", - "text": "Sent by LinuxGSM ${version}", - "emoji": true - } - ] - } - ] - } - ] -} EOF ) if [ -n "${querytype}" ]; then json+=$( cat << EOF + , { "type": "section", "text": { "type": "mrkdwn", "text": "*Is my Game Server Online?*\n" } - }, + } EOF ) fi @@ -104,82 +81,21 @@ fi if [ -n "${alerturl}" ]; then json+=$( cat << EOF + , { "type": "section", "text": { "type": "mrkdwn", "text": "*More info*\n<${alerturl}|${alerturl}>" } - }, + } EOF ) fi json+=$( cat << EOF -{ - "attachments": [ - { - "color": "${alertcolourhex}", - "blocks": [ - { - "type": "header", - "text": { - "type": "mrkdwn", - "text": "${alerttitle}", - "emoji": true - } - }, - { - "type": "divider" - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "*Server Name*\n${servername}" - } - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "*Information*\n${alertmessage}" - } - }, - { - "type": "section", - "fields": [ - { - "type": "mrkdwn", - "text": "*Game*\n${gamename}" - }, - { - "type": "mrkdwn", - "text": "*Server IP*\n\`${alertip}:${port}\`" - }, - { - "type": "mrkdwn", - "text": "*Hostname*\n${HOSTNAME}" - }, - { - "type": "mrkdwn", - "text": "*Server Time*\n$(date)" - } - ], - "accessory": { - "type": "image", - "image_url": "${alerticon}", - "alt_text": "cute cat" - } - }, - { - "type": "section", - "text": { - "type": "mrkdwn", - "text": "*Server Time*\n${alertmessage}" - } - }, + , { "type": "context", "elements": [ diff --git a/lgsm/modules/alert_telegram.sh b/lgsm/modules/alert_telegram.sh old mode 100644 new mode 100755 index d7c9b8447..ace95d4db --- a/lgsm/modules/alert_telegram.sh +++ b/lgsm/modules/alert_telegram.sh @@ -14,7 +14,7 @@ json=$( "message_thread_id": "${telegramthreadid}", "parse_mode": "HTML", "disable_notification": "${telegramdisablenotification}", - "text": "${alerttitle}\n\nServer name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\nHostname\n${HOSTNAME}\n\n + "text": "${alerttitle}\n\nServer Name\n${servername}\n\nInformation\n${alertmessage}\n\nGame\n${gamename}\n\nServer IP\n${alertip}:${port}\n\n EOF ) @@ -43,7 +43,13 @@ EOF ) fn_print_dots "Sending Telegram alert" -telegramsend=$(curl --connect-timeout 3 -sSL -H "Content-Type: application/json" -X POST -d "$(echo -n "${json}" | jq -c .)" ${curlcustomstring} "https://${telegramapi}/bot${telegramtoken}/sendMessage" | grep "error_code") + +curlcustomargs=() +if [ -n "${curlcustomstring}" ]; then + read -r -a curlcustomargs <<< "${curlcustomstring}" +fi + +telegramsend=$(curl --connect-timeout 3 -sSL -H "Content-Type: application/json" -X POST -d "$(echo -n "${json}" | jq -c .)" "${curlcustomargs[@]}" "https://${telegramapi}/bot${telegramtoken}/sendMessage" | grep "error_code") if [ -n "${telegramsend}" ]; then fn_print_fail_nl "Sending Telegram alert: ${telegramsend}" diff --git a/lgsm/modules/check.sh b/lgsm/modules/check.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_config.sh b/lgsm/modules/check_config.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh old mode 100644 new mode 100755 index edcdb6c7b..6d572fd40 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -75,11 +75,11 @@ fn_install_mono_repo() { # Run the mono repo install. eval "${cmd}" + monorepoexitcode=$? # Did Mono repo install correctly? if [ "${monoautoinstall}" != "1" ]; then - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then + if [ "${monorepoexitcode}" -ne 0 ]; then fn_print_failure_nl "Unable to install Mono repository." fn_script_log_fail "Unable to install Mono repository." else @@ -234,7 +234,7 @@ fn_install_missing_deps() { } fn_check_loop() { - # Loop though required depenencies checking if they are installed. + # Loop though required dependencies checking if they are installed. for deptocheck in "${array_deps_required[@]}"; do fn_deps_detector done diff --git a/lgsm/modules/check_executable.sh b/lgsm/modules/check_executable.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_gamedig.sh b/lgsm/modules/check_gamedig.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_glibc.sh b/lgsm/modules/check_glibc.sh old mode 100644 new mode 100755 index 8b3d00658..e49b461f6 --- a/lgsm/modules/check_glibc.sh +++ b/lgsm/modules/check_glibc.sh @@ -17,7 +17,7 @@ elif [ -z "${glibc}" ]; then fn_print_error_nl "Checking glibc: requirement unknown" fn_script_log_error "Checking glibc: requirement unknown" fn_sleep_time_5 -elif [ "$(printf '%s\n'${glibc}'\n' "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then +elif [ "$(printf '%s\n' "${glibc}" "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then fn_print_dots "Checking glibc" fn_print_error_nl "Checking glibc: requirements not met" fn_script_log_error "Checking glibc: requirements not met" diff --git a/lgsm/modules/check_ip.sh b/lgsm/modules/check_ip.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_last_update.sh b/lgsm/modules/check_last_update.sh old mode 100644 new mode 100755 index 2686c6507..a68285344 --- a/lgsm/modules/check_last_update.sh +++ b/lgsm/modules/check_last_update.sh @@ -11,6 +11,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" if [ -f "${lockdir}/${selfname}-last-started.lock" ]; then laststart=$(cat "${lockdir}/${selfname}-last-started.lock") fi + if [ -f "${lockdir}/last-updated.lock" ]; then lastupdate=$(cat "${lockdir}/last-updated.lock") fi diff --git a/lgsm/modules/check_logs.sh b/lgsm/modules/check_logs.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_permissions.sh b/lgsm/modules/check_permissions.sh old mode 100644 new mode 100755 index 4004732f2..73fba983d --- a/lgsm/modules/check_permissions.sh +++ b/lgsm/modules/check_permissions.sh @@ -249,7 +249,7 @@ fn_sys_perm_error_process() { fi } -## Run permisions checks when not root. +## Run permissions checks when not root. if [ "$(whoami)" != "root" ]; then fn_check_ownership fn_check_permissions diff --git a/lgsm/modules/check_root.sh b/lgsm/modules/check_root.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_status.sh b/lgsm/modules/check_status.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_steamcmd.sh b/lgsm/modules/check_steamcmd.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_system_dir.sh b/lgsm/modules/check_system_dir.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_system_requirements.sh b/lgsm/modules/check_system_requirements.sh old mode 100644 new mode 100755 index 39cef3a42..f34190fec --- a/lgsm/modules/check_system_requirements.sh +++ b/lgsm/modules/check_system_requirements.sh @@ -71,7 +71,7 @@ fi if [ "${ramrequirementgb}" ]; then if (($(echo "${physmemtotalgb} < ${ramrequirementgb}" | bc -l))); then fn_print_dots "Checking RAM" - fn_print_warn_nl "Checking RAM: Minumum RAM requirements not met" + fn_print_warn_nl "Checking RAM: Minimum RAM requirements not met" fn_print_nl "* ${ramrequirementgb}G is required, but only ${physmemtotal} is available." fn_print_nl "* ${gamename} server may fail to run or experience poor performance." fn_sleep_time_5 diff --git a/lgsm/modules/check_tmuxception.sh b/lgsm/modules/check_tmuxception.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/check_version.sh b/lgsm/modules/check_version.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_backup.sh b/lgsm/modules/command_backup.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_console.sh b/lgsm/modules/command_console.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_debug.sh b/lgsm/modules/command_debug.sh old mode 100644 new mode 100755 index a5dae7615..e502605f2 --- a/lgsm/modules/command_debug.sh +++ b/lgsm/modules/command_debug.sh @@ -49,7 +49,7 @@ if [ -n "${glibc}" ]; then : elif [ -z "${glibc}" ]; then echo -e "${lightblue}glibc required:\t${red}UNKNOWN${default}" - elif [ "$(printf '%s\n'${glibc}'\n' ${glibcversion} | sort -V | head -n 1)" != "${glibc}" ]; then + elif [ "$(printf '%s\n' "${glibc}" "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then echo -e "${lightblue}glibc required:\t${red}${glibc} ${default}(${red}distro glibc ${glibcversion} too old${default})" else echo -e "${lightblue}glibc required:\t${green}${glibc}${default}" diff --git a/lgsm/modules/command_details.sh b/lgsm/modules/command_details.sh old mode 100644 new mode 100755 index 8de2ddeb5..047f50c6f --- a/lgsm/modules/command_details.sh +++ b/lgsm/modules/command_details.sh @@ -29,7 +29,7 @@ fn_info_messages_gameserver_resource fn_info_messages_gameserver fn_info_messages_script fn_info_messages_backup -# Some game servers do not have parms. +# Some game servers do not have params. if [ "${shortname}" != "jc2" ] && [ "${shortname}" != "dst" ] && [ "${shortname}" != "pz" ] && [ "${engine}" != "renderware" ]; then fn_info_messages_commandlineparms fi diff --git a/lgsm/modules/command_dev_clear_modules.sh b/lgsm/modules/command_dev_clear_modules.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_dev_debug.sh b/lgsm/modules/command_dev_debug.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_dev_detect_deps.sh b/lgsm/modules/command_dev_detect_deps.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_dev_detect_glibc.sh b/lgsm/modules/command_dev_detect_glibc.sh old mode 100644 new mode 100755 index 20398bd47..5af93466b --- a/lgsm/modules/command_dev_detect_glibc.sh +++ b/lgsm/modules/command_dev_detect_glibc.sh @@ -63,7 +63,7 @@ for glibc_check_var in "${glibc_check_dir_array[@]}"; do cat "${tmpdir}/detect_glibc_${glibc_check_var}.tmp" | sort | uniq | sort -r --version-sort | head -1 | tee -a "${tmpdir}/detect_glibc_highest.tmp" echo -e "" echo -e "Files requiring GLIBC" - echo -e "Highest verion required: filename" + echo -e "Highest version required: filename" cat "${tmpdir}/detect_glibc_files_${glibc_check_var}.tmp" echo -e "" echo -e "All required GLIBC versions" diff --git a/lgsm/modules/command_dev_detect_ldd.sh b/lgsm/modules/command_dev_detect_ldd.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_dev_parse_distro_details.sh b/lgsm/modules/command_dev_parse_distro_details.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_dev_parse_game_details.sh b/lgsm/modules/command_dev_parse_game_details.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_dev_query_raw.sh b/lgsm/modules/command_dev_query_raw.sh old mode 100644 new mode 100755 index b95ef6c33..61b4d7a70 --- a/lgsm/modules/command_dev_query_raw.sh +++ b/lgsm/modules/command_dev_query_raw.sh @@ -249,9 +249,9 @@ echo -e "${bold}${lightyellow}Query Port (${queryport}) - TCP Output${default}" fn_messages_separator echo -e "" for queryip in "${queryips[@]}"; do - echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${queryport}''${default}" + echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'\"${queryip}\"'/'\"${queryport}\"''${default}" echo -e "" - timeout 3 bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${queryport}'' + timeout 3 bash -c 'exec 3<> /dev/tcp/'"${queryip}"'/'"${queryport}"'' querystatus="$?" echo -e "" if [ "${querystatus}" == "0" ]; then @@ -268,9 +268,9 @@ echo -e "${lightgreen}TCP Raw Output${default}" fn_messages_separator echo -e "" for queryip in "${queryips[@]}"; do - echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${port}''${default}" + echo -e "${italic}bash -c 'exec 3<> /dev/tcp/'\"${queryip}\"'/'\"${port}\"''${default}" echo -e "" - timeout 3 bash -c 'exec 3<> /dev/tcp/'${queryip}'/'${port}'' + timeout 3 bash -c 'exec 3<> /dev/tcp/'"${queryip}"'/'"${port}"'' querystatus="$?" echo -e "" if [ "${querystatus}" == "0" ]; then diff --git a/lgsm/modules/command_dev_ui.sh b/lgsm/modules/command_dev_ui.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_fastdl.sh b/lgsm/modules/command_fastdl.sh old mode 100644 new mode 100755 index 3b8165444..dfdcc9ec8 --- a/lgsm/modules/command_fastdl.sh +++ b/lgsm/modules/command_fastdl.sh @@ -219,7 +219,7 @@ fn_fastdl_preview() { core_exit.sh fi - if [ "${engine}" == "source" ]; then + if [ "${engine}" == "source" ]; then echo -e "about to compress ${totalfiles} files, total size $(fn_human_readable_file_size "${filesizetotal}" 0)" elif [ "${engine}" == "goldsrc" ]; then echo -e "about to copy ${totalfiles} files, total size $(fn_human_readable_file_size "${filesizetotal}" 0)" diff --git a/lgsm/modules/command_install.sh b/lgsm/modules/command_install.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_install_resources_mta.sh b/lgsm/modules/command_install_resources_mta.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_mods_install.sh b/lgsm/modules/command_mods_install.sh old mode 100644 new mode 100755 index e76f3f1fa..a8f90293b --- a/lgsm/modules/command_mods_install.sh +++ b/lgsm/modules/command_mods_install.sh @@ -47,7 +47,7 @@ while [ "${compatiblemodslistindex}" -lt "${#compatiblemodslist[@]}" ]; do echo -e "${displayedmodname} - ${displayedmoddescription} - ${displayedmodsite}" echo -e " * ${cyan}${displayedmodcommand}${default}" # Increment index from the amount of values we just displayed. - let "compatiblemodslistindex+=4" + ((compatiblemodslistindex += 4)) ((totalmodsavailable++)) done @@ -61,16 +61,29 @@ fn_script_log_info "${totalmodsavailable} addons/mods are available for install" ## User selects a mod. echo -e "" -while [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; do + +while :; do echo -en "Enter an ${cyan}addon/mod${default} to ${green}install${default} (or exit to abort): " read -r usermodselect # Exit if user says exit or abort. if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then core_exit.sh - # Supplementary output upon invalid user input. - elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then - fn_print_error2_nl "${usermodselect} is not a valid addon/mod." fi + + validselection=0 + for availablemodcommand in "${availablemodscommands[@]}"; do + if [ "${availablemodcommand}" == "${usermodselect}" ]; then + validselection=1 + break + fi + done + + if [ "${validselection}" -eq 1 ]; then + break + fi + + # Supplementary output upon invalid user input. + fn_print_error2_nl "${usermodselect} is not a valid addon/mod." done # Get mod info. currentmod="${usermodselect}" diff --git a/lgsm/modules/command_mods_remove.sh b/lgsm/modules/command_mods_remove.sh old mode 100644 new mode 100755 index 589046b11..04240eb60 --- a/lgsm/modules/command_mods_remove.sh +++ b/lgsm/modules/command_mods_remove.sh @@ -32,16 +32,29 @@ done echo -e "" # Keep prompting as long as the user input doesn't correspond to an available mod. -while [[ ! " ${installedmodslist[@]} " =~ " ${usermodselect} " ]]; do + +while :; do echo -en "Enter an ${cyan}addon/mod${default} to ${red}remove${default} (or exit to abort): " read -r usermodselect # Exit if user says exit or abort. if [ "${usermodselect}" == "exit" ] || [ "${usermodselect}" == "abort" ]; then core_exit.sh - # Supplementary output upon invalid user input. - elif [[ ! " ${availablemodscommands[@]} " =~ " ${usermodselect} " ]]; then - fn_print_error2_nl "${usermodselect} is not a valid addon/mod." fi + + validselection=0 + for installedmodcommand in "${installedmodslist[@]}"; do + if [ "${installedmodcommand}" == "${usermodselect}" ]; then + validselection=1 + break + fi + done + + if [ "${validselection}" -eq 1 ]; then + break + fi + + # Supplementary output upon invalid user input. + fn_print_error2_nl "${usermodselect} is not a valid addon/mod." done fn_print_warning_nl "You are about to remove ${cyan}${usermodselect}${default}." diff --git a/lgsm/modules/command_mods_update.sh b/lgsm/modules/command_mods_update.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_monitor.sh b/lgsm/modules/command_monitor.sh old mode 100644 new mode 100755 index 5fa3c3000..7c813aed7 --- a/lgsm/modules/command_monitor.sh +++ b/lgsm/modules/command_monitor.sh @@ -164,8 +164,8 @@ fn_monitor_check_update_source() { fn_script_log_info "Checking update: CHECKING" fn_print_ok "Checking update" fn_print_ok_eol_nl - fn_script_log_info "Checking update: ${selfname} has requested an update and needs to be restarted" - alert="update-request" + fn_script_log_info "Checking update: ${selfname} has requested a restart for an update to be applied" + alert="update-restart-request" alert.sh command_restart.sh core_exit.sh diff --git a/lgsm/modules/command_postdetails.sh b/lgsm/modules/command_postdetails.sh old mode 100644 new mode 100755 index 7f5f67304..d029093b5 --- a/lgsm/modules/command_postdetails.sh +++ b/lgsm/modules/command_postdetails.sh @@ -46,7 +46,7 @@ else fn_info_messages_gameserver fn_info_messages_script fn_info_messages_backup - # Some game servers do not have parms. + # Some game servers do not have params. if [ "${shortname}" != "jc2" ] && [ "${shortname}" != "jc3" ] && [ "${shortname}" != "dst" ] && [ "${shortname}" != "pz" ] && [ "${engine}" != "renderware" ]; then fn_info_messages_commandlineparms fi @@ -59,7 +59,7 @@ fi fn_print_dots "termbin.com" link=$(cat "${postdetailslog}" | { - nc -w 3 termbin.com 9999 + nc -w 10 termbin.com 9999 echo $? > /tmp/nc_exit_status } | tr -d '\n\0') nc_exit_status=$(cat /tmp/nc_exit_status) diff --git a/lgsm/modules/command_restart.sh b/lgsm/modules/command_restart.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_send.sh b/lgsm/modules/command_send.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_skeleton.sh b/lgsm/modules/command_skeleton.sh old mode 100644 new mode 100755 index b9f51205a..687790a37 --- a/lgsm/modules/command_skeleton.sh +++ b/lgsm/modules/command_skeleton.sh @@ -3,7 +3,7 @@ # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com -# Description: Creates an copy of a game servers directorys. +# Description: Creates an copy of a game servers directories. commandname="SKELETON" commandaction="Skeleton" @@ -13,7 +13,7 @@ fn_firstcommand_set fn_print_dots "Creating skeleton directory" check.sh -# Find all directorys and create them in the skel directory +# Find all directories and create them in the skel directory find "${rootdir}" -type d -not \( -path ./skel -prune \) | cpio -pdvm skel 2> /dev/null exitcode=$? if [ "${exitcode}" -ne 0 ]; then diff --git a/lgsm/modules/command_start.sh b/lgsm/modules/command_start.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_stop.sh b/lgsm/modules/command_stop.sh old mode 100644 new mode 100755 index f1edc3544..ab827314d --- a/lgsm/modules/command_stop.sh +++ b/lgsm/modules/command_stop.sh @@ -16,7 +16,7 @@ fn_stop_graceful_ctrlc() { fn_script_log_info "Graceful: CTRL+c" # Sends CTRL+c. tmux -L "${socketname}" send-keys -t "${sessionname}" C-c > /dev/null 2>&1 - # Waits up to 30 seconds giving the server time to shutdown gracefuly. + # Waits up to 30 seconds giving the server time to shutdown gracefully. for seconds in {1..30}; do check_status.sh if [ "${status}" == "0" ]; then @@ -293,7 +293,7 @@ fn_stop_graceful_avorion() { fn_sleep_time_5 # Sends /quit. tmux -L "${socketname}" send-keys -t "${sessionname}" /stop ENTER > /dev/null 2>&1 - # Waits up to 30 seconds giving the server time to shutdown gracefuly. + # Waits up to 30 seconds giving the server time to shutdown gracefully. for seconds in {1..30}; do check_status.sh if [ "${status}" == "0" ]; then diff --git a/lgsm/modules/command_test_alert.sh b/lgsm/modules/command_test_alert.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_ts3_server_pass.sh b/lgsm/modules/command_ts3_server_pass.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_update_linuxgsm.sh b/lgsm/modules/command_update_linuxgsm.sh old mode 100644 new mode 100755 index 3299be509..3fd4cc681 --- a/lgsm/modules/command_update_linuxgsm.sh +++ b/lgsm/modules/command_update_linuxgsm.sh @@ -16,8 +16,9 @@ info_distro.sh info_game.sh # Prevent github from using a cached version of the file if dev-debug is enabled. +nocache=() if [ -f "${rootdir}/.dev-debug" ]; then - nocache="-H \"Cache-Control: no-cache\" -H \"Pragma: no-cache\"" + nocache=(-H "Cache-Control: no-cache" -H "Pragma: no-cache") fi fn_script_log_info "Updating LinuxGSM" @@ -26,10 +27,10 @@ fn_print_dots "Selecting repo" fn_script_log_info "Selecting repo" # Select remotereponame -curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null +curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null exitcode=$? if [ "${exitcode}" -ne "0" ]; then - curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null exitcode=$? if [ "${exitcode}" -ne "0" ]; then fn_print_fail_nl "Selecting repo: Unable to to access GitHub or Bitbucket repositories" @@ -47,9 +48,9 @@ fi # Check linuxsm.sh echo -en "checking ${remotereponame} script [ ${italic}linuxgsm.sh${default} ]\c" if [ "${remotereponame}" == "GitHub" ]; then - curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh" 1> /dev/null else - curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh" 1> /dev/null fi exitcode=$? if [ "${exitcode}" -ne 0 ]; then @@ -60,9 +61,9 @@ if [ "${exitcode}" -ne 0 ]; then fi if [ "${remotereponame}" == "GitHub" ]; then - tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh")) + tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/linuxgsm.sh")) else - tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh")) + tmp_script_diff=$(diff "${tmpdir}/linuxgsm.sh" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/linuxgsm.sh")) fi if [ "${tmp_script_diff}" != "" ]; then @@ -130,9 +131,9 @@ fi echo -en "checking ${remotereponame} config [ ${italic}_default.cfg${default} ]\c" fn_script_log_info "Checking ${remotereponame} config _default.cfg" if [ "${remotereponame}" == "GitHub" ]; then - curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null else - curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg" 1> /dev/null fi exitcode=$? if [ "${exitcode}" -ne 0 ]; then @@ -143,9 +144,9 @@ if [ "${exitcode}" -ne 0 ]; then fi if [ "${remotereponame}" == "GitHub" ]; then - config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg")) + config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg")) else - config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg")) + config_file_diff=$(diff "${configdirdefault}/config-lgsm/${gameservername}/_default.cfg" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/config-default/config-lgsm/${gameservername}/_default.cfg")) fi if [ "${config_file_diff}" != "" ]; then @@ -165,9 +166,9 @@ if [ -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then echo -en "checking ${remotereponame} config [ ${italic}${distroid}-${distroversioncsv}.csv${default} ]\c" fn_script_log_info "Checking ${remotereponame} ${distroid}-${distroversioncsv}.csv" if [ "${remotereponame}" == "GitHub" ]; then - curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null else - curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv" 1> /dev/null fi exitcode=$? if [ "${exitcode}" -ne 0 ]; then @@ -178,9 +179,9 @@ if [ -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then fi if [ "${remotereponame}" == "GitHub" ]; then - config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv")) + config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv")) else - config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv")) + config_file_diff=$(diff "${datadir}/${distroid}-${distroversioncsv}.csv" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/lgsm/data/${distroid}-${distroversioncsv}.csv")) fi if [ "${config_file_diff}" != "" ]; then @@ -204,9 +205,9 @@ if [ -n "${modulesdir}" ]; then echo -en "checking ${remotereponame} module [ ${italic}${modulefile}${default} ]\c" github_file_url_dir="lgsm/modules" if [ "${remotereponame}" == "GitHub" ]; then - curl ${nocache} --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null else - curl ${nocache} --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null + curl "${nocache[@]}" --connect-timeout 3 -IsfL "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}" 1> /dev/null fi exitcode=$? if [ "${exitcode}" -ne 0 ]; then @@ -224,9 +225,9 @@ if [ -n "${modulesdir}" ]; then else # compare file if [ "${remotereponame}" == "GitHub" ]; then - module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl ${nocache} --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}")) + module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://raw.githubusercontent.com/${githubuser}/${githubrepo}/${githubbranch}/${github_file_url_dir}/${modulefile}")) else - module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl ${nocache} --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}")) + module_file_diff=$(diff "${modulesdir}/${modulefile}" <(curl "${nocache[@]}" --connect-timeout 3 -s "https://bitbucket.org/${githubuser}/${githubrepo}/raw/${githubbranch}/${github_file_url_dir}/${modulefile}")) fi # results diff --git a/lgsm/modules/command_validate.sh b/lgsm/modules/command_validate.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/command_wipe.sh b/lgsm/modules/command_wipe.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/compress_unreal_maps.sh b/lgsm/modules/compress_unreal_maps.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh old mode 100644 new mode 100755 index 3b9ec9945..0a0dacb29 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -46,6 +46,18 @@ fn_dl_steamcmd() { validate="validate" fi + # steamcmdcommand can contain multiple arguments; treat it as an argv array. + steamcmdcommandarray=() + read -r -a steamcmdcommandarray <<< "${steamcmdcommand}" + unbuffercommand=() + if [ -n "${unbuffer}" ]; then + unbuffercommand=("${unbuffer}") + fi + validateparam=() + if [ -n "${validate}" ]; then + validateparam=("${validate}") + fi + # To do error checking for SteamCMD the output of steamcmd will be saved to a log. steamcmdlog="${lgsmlogdir}/${selfname}-steamcmd.log" @@ -61,29 +73,29 @@ fn_dl_steamcmd() { if [ "${appid}" == "90" ]; then # If using a specific branch. if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - ${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" elif [ -n "${branch}" ]; then - ${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" else - ${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_set_config 90 mod "${appidmod}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" fi # Force Windows Platform type. elif [ "${steamcmdforcewindows}" == "yes" ]; then if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - ${unbuffer} ${steamcmdcommand} +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" elif [ -n "${branch}" ]; then - ${unbuffer} ${steamcmdcommand} +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" else - ${unbuffer} ${steamcmdcommand} +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" fi # All other servers. else if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then - ${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" elif [ -n "${branch}" ]; then - ${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" else - ${unbuffer} ${steamcmdcommand} +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" ${validate} +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" fi fi @@ -132,9 +144,9 @@ fn_dl_steamcmd() { fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Corrupt update files" fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Corrupt update files" else - fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Unknown error occured" + fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Unknown error occurred" fn_print_nl "Please provide content log to LinuxGSM developers https://linuxgsm.com/steamcmd-error" - fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Unknown error occured" + fn_script_log_error "${commandaction} ${selfname}: ${remotelocation}: Unknown error occurred" fi elif [ "${exitcode}" -ne 0 ]; then fn_print_error2_nl "${commandaction} ${selfname}: ${remotelocation}: Exit code: ${exitcode}" @@ -188,8 +200,8 @@ fn_dl_hash() { hashbin="sha512sum" hashtype="SHA512" else - fn_script_log_error "hash lengh not known for hash type" - fn_print_error_nl "hash lengh not known for hash type" + fn_script_log_error "hash length not known for hash type" + fn_print_error_nl "hash length not known for hash type" core_exit.sh fi echo -en "verifying ${local_filename} with ${hashtype}..." diff --git a/lgsm/modules/core_exit.sh b/lgsm/modules/core_exit.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/core_github.sh b/lgsm/modules/core_github.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/core_legacy.sh b/lgsm/modules/core_legacy.sh old mode 100644 new mode 100755 index 1d5bc430c..55c2172d4 --- a/lgsm/modules/core_legacy.sh +++ b/lgsm/modules/core_legacy.sh @@ -3,7 +3,7 @@ # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com -# Description: Code for backwards compatability with older versions of LinuxGSM. +# Description: Code for backwards compatibility with older versions of LinuxGSM. moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" diff --git a/lgsm/modules/core_logs.sh b/lgsm/modules/core_logs.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/core_messages.sh b/lgsm/modules/core_messages.sh old mode 100644 new mode 100755 index 37c2e98b5..da5fd43e3 --- a/lgsm/modules/core_messages.sh +++ b/lgsm/modules/core_messages.sh @@ -560,7 +560,7 @@ fn_print_restart_warning() { } # Functions below are used to ensure that logs and UI correctly reflect the command it is actually running. -# Useful when a command has to call upon another command causing the other command to overrite commandname variables +# Useful when a command has to call upon another command causing the other command to overwrite commandname variables # Used to remember the command that ran first. fn_firstcommand_set() { diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh old mode 100644 new mode 100755 index 614f5d019..2cc635888 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -14,31 +14,13 @@ modulesversion="v25.2.0" core_dl.sh() { modulefile="${FUNCNAME[0]}" - if [ "$(type fn_fetch_core_dl 2>/dev/null)" ]; then + if [ "$(type fn_fetch_core_dl 2> /dev/null)" ]; then fn_fetch_core_dl "lgsm/modules" "core_dl.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" else fn_bootstrap_fetch_file_github "lgsm/modules" "core_dl.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" fi } -core_messages.sh() { - modulefile="${FUNCNAME[0]}" - if [ "$(type fn_fetch_core_dl 2>/dev/null)" ]; then - fn_fetch_core_dl "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" - else - fn_bootstrap_fetch_file_github "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" - fi -} - -core_legacy.sh() { - modulefile="${FUNCNAME[0]}" - if [ "$(type fn_fetch_core_dl 2>/dev/null)" ]; then - fn_fetch_core_dl "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" - else - fn_bootstrap_fetch_file_github "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" - fi -} - core_exit.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -54,17 +36,35 @@ core_getopt.sh() { fn_fetch_module } -core_trap.sh() { +core_github.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } +core_legacy.sh() { + modulefile="${FUNCNAME[0]}" + if [ "$(type fn_fetch_core_dl 2> /dev/null)" ]; then + fn_fetch_core_dl "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" + else + fn_bootstrap_fetch_file_github "lgsm/modules" "core_legacy.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" + fi +} + +core_messages.sh() { + modulefile="${FUNCNAME[0]}" + if [ "$(type fn_fetch_core_dl 2> /dev/null)" ]; then + fn_fetch_core_dl "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" + else + fn_bootstrap_fetch_file_github "lgsm/modules" "core_messages.sh" "${modulesdir}" "chmodx" "run" "noforcedl" "nohash" + fi +} + core_steamcmd.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -core_github.sh() { +core_trap.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -91,87 +91,87 @@ command_details.sh() { fn_fetch_module } -command_sponsor.sh() { +command_fastdl.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_postdetails.sh() { +command_install.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_test_alert.sh() { +command_install_resources_mta.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_monitor.sh() { +command_mods_install.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_start.sh() { +command_mods_remove.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_stop.sh() { +command_mods_update.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_validate.sh() { +command_monitor.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_install.sh() { +command_postdetails.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_install_resources_mta.sh() { +command_restart.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -install_squad_license.sh() { +command_send.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_mods_install.sh() { +command_skeleton.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_mods_update.sh() { +command_sponsor.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_mods_remove.sh() { +command_start.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_fastdl.sh() { +command_stop.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_ts3_server_pass.sh() { +command_test_alert.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_restart.sh() { +command_ts3_server_pass.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_skeleton.sh() { +command_validate.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -181,7 +181,7 @@ command_wipe.sh() { fn_fetch_module } -command_send.sh() { +install_squad_license.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -277,12 +277,12 @@ compress_unreal2_maps.sh() { # Mods -mods_list.sh() { +mods_core.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -mods_core.sh() { +mods_list.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -299,37 +299,37 @@ command_dev_debug.sh() { fn_fetch_module } -command_dev_parse_game_details.sh() { +command_dev_detect_deps.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_dev_parse_distro_details.sh() { +command_dev_detect_glibc.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_dev_detect_deps.sh() { +command_dev_detect_ldd.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_dev_detect_glibc.sh() { +command_dev_parse_distro_details.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_dev_detect_ldd.sh() { +command_dev_parse_game_details.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_dev_ui.sh() { +command_dev_query_raw.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_dev_query_raw.sh() { +command_dev_ui.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -346,27 +346,27 @@ fix_ark.sh() { fn_fetch_module } -fix_av.sh() { +fix_arma3.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_arma3.sh() { +fix_armar.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_armar.sh() { +fix_av.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_bt.sh() { +fix_bo.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_bo.sh() { +fix_bt.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -446,67 +446,62 @@ fix_rw.sh() { fn_fetch_module } -fix_sfc.sh() { - modulefile="${FUNCNAME[0]}" - fn_fetch_module -} - -fix_sm.sh() { +fix_samp.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_st.sh() { +fix_sfc.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_steamcmd.sh() { +fix_sm.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_terraria.sh() { +fix_sof2.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_tf2.sh() { +fix_squad.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_ut3.sh() { +fix_st.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_rust.sh() { +fix_steamcmd.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_samp.sh() { +fix_terraria.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_sdtd.sh() { +fix_tf2.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_sof2.sh() { +fix_ts3.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_squad.sh() { +fix_unt.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fix_ts3.sh() { +fix_ut.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -516,12 +511,7 @@ fix_ut2k4.sh() { fn_fetch_module } -fix_ut.sh() { - modulefile="${FUNCNAME[0]}" - fn_fetch_module -} - -fix_unt.sh() { +fix_ut3.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -585,27 +575,27 @@ alert_email.sh() { fn_fetch_module } -alert_ifttt.sh() { +alert_gotify.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -alert_pushbullet.sh() { +alert_ifttt.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -alert_pushover.sh() { +alert_ntfy.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -alert_gotify.sh() { +alert_pushbullet.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -alert_telegram.sh() { +alert_pushover.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -620,10 +610,11 @@ alert_slack.sh() { fn_fetch_module } -alert_ntfy.sh() { +alert_telegram.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } + # Logs core_logs.sh() { @@ -639,58 +630,57 @@ query_gamedig.sh() { } # Update - -command_update_modules.sh() { +command_check_update.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_update_linuxgsm.sh() { +command_update.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_update.sh() { +command_update_linuxgsm.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -command_check_update.sh() { +command_update_modules.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -update_ts3.sh() { +fn_update_modules.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -update_mc.sh() { +update_fctr.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -update_mcb.sh() { +update_jk2.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -update_pmc.sh() { +update_mc.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -update_mta.sh() { +update_mcb.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -update_fctr.sh() { +update_mta.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -update_jk2.sh() { +update_pmc.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -700,7 +690,7 @@ update_steamcmd.sh() { fn_fetch_module } -update_vints.sh() { +update_ts3.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -710,12 +700,12 @@ update_ut99.sh() { fn_fetch_module } -update_xnt.sh() { +update_vints.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -fn_update_modules.sh() { +update_xnt.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -723,6 +713,10 @@ fn_update_modules.sh() { # ## Installer modules # +check_gamedig.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} fn_autoinstall() { autoinstall=1 @@ -739,32 +733,32 @@ install_config.sh() { fn_fetch_module } -install_factorio_save.sh() { +install_dl_ut2k4.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -check_gamedig.sh() { +install_dst_token.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -install_dst_token.sh() { +install_eula.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -install_eula.sh() { +install_factorio_save.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -install_gsquery.sh() { +install_gslt.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } -install_gslt.sh() { +install_gsquery.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } @@ -788,6 +782,7 @@ install_server_dir.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module } + install_server_files.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module @@ -818,11 +813,6 @@ install_ut2k4.sh() { fn_fetch_module } -install_dl_ut2k4.sh() { - modulefile="${FUNCNAME[0]}" - fn_fetch_module -} - install_ut2k4_key.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/core_steamcmd.sh b/lgsm/modules/core_steamcmd.sh old mode 100644 new mode 100755 index bf9790132..d265f577d --- a/lgsm/modules/core_steamcmd.sh +++ b/lgsm/modules/core_steamcmd.sh @@ -185,12 +185,12 @@ fn_update_steamcmd_remotebuild() { fi # password for branch not needed to check the buildid - remotebuildversion=$(${steamcmdcommand} +login "${steamuser}" "${steampass}" +app_info_request "${appid}" +login "${steamuser}" "${steampass}" +app_info_update 1 +app_info_print "${appid}" +quit | sed -e '/"branches"/,/^}/!d' | sed -n "/\"${branch}\"/,/}/p" | grep -m 1 buildid | tr -cd '[:digit:]') + remotebuild=$(${steamcmdcommand} +login "${steamuser}" "${steampass}" +app_info_request "${appid}" +login "${steamuser}" "${steampass}" +app_info_update 1 +app_info_print "${appid}" +quit | sed -e '/"branches"/,/^}/!d' | sed -n "/\"${branch}\"/,/}/p" | grep -m 1 buildid | tr -cd '[:digit:]') if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -200,7 +200,7 @@ fn_update_steamcmd_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -211,14 +211,14 @@ fn_update_steamcmd_remotebuild() { fn_update_steamcmd_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" fn_print "\n" fn_print_nl "${bold}${underline}Update${default} available" fn_print_nl "* Local build: ${red}${localbuild}${default}" - fn_print_nl "* Remote build: ${green}${remotebuildversion}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then fn_print_nl "* Branch: ${branch}" fi @@ -229,16 +229,17 @@ fn_update_steamcmd_compare() { fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -n "${betapassword}" ]; then fn_script_log_info "Branch password: ${betapassword}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -257,7 +258,6 @@ fn_update_steamcmd_compare() { fn_firstcommand_reset fi unset exitbypass - date +%s > "${lockdir:?}/last-updated.lock" alert="update" elif [ "${commandname}" == "CHECK-UPDATE" ]; then alert="check-update" @@ -268,7 +268,7 @@ fn_update_steamcmd_compare() { fn_print "\n" fn_print_nl "${bold}${underline}No update${default} available" fn_print_nl "* Local build: ${green}${localbuild}${default}" - fn_print_nl "* Remote build: ${green}${remotebuildversion}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then fn_print_nl "* Branch: ${branch}" fi @@ -279,7 +279,7 @@ fn_update_steamcmd_compare() { fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi diff --git a/lgsm/modules/core_trap.sh b/lgsm/modules/core_trap.sh old mode 100644 new mode 100755 index 4b66b3937..f9ff17ff1 --- a/lgsm/modules/core_trap.sh +++ b/lgsm/modules/core_trap.sh @@ -8,10 +8,12 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_exit_trap() { + local saved_exit_status=$? + echo -e "" if [ -z "${exitcode}" ]; then - exitcode=$? + exitcode=${saved_exit_status} fi - echo -e "" + if [ -z "${exitcode}" ]; then exitcode=0 fi diff --git a/lgsm/modules/fix.sh b/lgsm/modules/fix.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_ark.sh b/lgsm/modules/fix_ark.sh old mode 100644 new mode 100755 index 366d137dd..3d6913d00 --- a/lgsm/modules/fix_ark.sh +++ b/lgsm/modules/fix_ark.sh @@ -7,7 +7,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -# removes mulitple appworkshop_346110.acf if found. +# removes multiple appworkshop_346110.acf if found. steamappsfilewc="$(find "${HOME}" -name appworkshop_346110.acf | wc -l)" if [ "${steamappsfilewc}" -gt "1" ]; then fixname="multiple appworkshop acf files" @@ -15,7 +15,7 @@ if [ "${steamappsfilewc}" -gt "1" ]; then find "${HOME}" -name appworkshop_346110.acf -exec rm -f {} \; fn_fix_msg_end elif [ "${steamappsfilewc}" -eq "1" ]; then - # Steam mods directory selecter + # Steam mods directory selector # This allows LinxuGSM to select either ~/.steam or ~/Steam. depending on what is being used steamappsfile=$(find "${HOME}" -name appworkshop_346110.acf) steamappsdir=$(dirname "${steamappsfile}") diff --git a/lgsm/modules/fix_arma3.sh b/lgsm/modules/fix_arma3.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_av.sh b/lgsm/modules/fix_av.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_bo.sh b/lgsm/modules/fix_bo.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_cmw.sh b/lgsm/modules/fix_cmw.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_csgo.sh b/lgsm/modules/fix_csgo.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_dst.sh b/lgsm/modules/fix_dst.sh old mode 100644 new mode 100755 index 2848fa5bb..e4fcc5a1c --- a/lgsm/modules/fix_dst.sh +++ b/lgsm/modules/fix_dst.sh @@ -8,7 +8,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" # Fixes: ./dontstarve_dedicated_server_nullrenderer: ./lib32/libcurl-gnutls.so.4: no version information available (required by ./dontstarve_dedicated_server_nullrenderer). -# Issue only occures on CentOS as libcurl-gnutls.so.4 is called libcurl.so.4 on CentOS. +# Issue only occurs on CentOS as libcurl-gnutls.so.4 is called libcurl.so.4 on CentOS. if [ -f "/etc/redhat-release" ] && [ ! -f "${serverfiles}/bin/lib32/libcurl-gnutls.so.4" ]; then fixname="libcurl-gnutls.so.4" fn_fix_msg_start diff --git a/lgsm/modules/fix_hw.sh b/lgsm/modules/fix_hw.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_ins.sh b/lgsm/modules/fix_ins.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_kf.sh b/lgsm/modules/fix_kf.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_kf2.sh b/lgsm/modules/fix_kf2.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_mcb.sh b/lgsm/modules/fix_mcb.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_mta.sh b/lgsm/modules/fix_mta.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_nmrih.sh b/lgsm/modules/fix_nmrih.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_onset.sh b/lgsm/modules/fix_onset.sh old mode 100644 new mode 100755 index 6430e5d6b..eeb18f0e2 --- a/lgsm/modules/fix_onset.sh +++ b/lgsm/modules/fix_onset.sh @@ -10,7 +10,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" export LD_LIBRARY_PATH="$LD_LIBRARY_PATH:${serverfiles}" # Fixes: Failed loading "mariadb": libmariadbclient.so.18: cannot open shared object file: No such file or directory -# Issue only occures on CentOS as libmariadbclient.so.18 is called libmariadb.so.3 on CentOS. +# Issue only occurs on CentOS as libmariadbclient.so.18 is called libmariadb.so.3 on CentOS. if [ -f "/etc/redhat-release" ] && [ ! -f "${serverfiles}/libmariadbclient.so.18" ] && [ -f "/usr/lib64/libmariadb.so.3" ]; then fixname="libmariadbclient.so.18" fn_fix_msg_start diff --git a/lgsm/modules/fix_pvr.sh b/lgsm/modules/fix_pvr.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_ro.sh b/lgsm/modules/fix_ro.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_rust.sh b/lgsm/modules/fix_rust.sh old mode 100644 new mode 100755 index 80c790a59..167a5183d --- a/lgsm/modules/fix_rust.sh +++ b/lgsm/modules/fix_rust.sh @@ -23,7 +23,7 @@ if [ -z "${seed}" ] || [ "${seed}" == "0" ]; then randomseed=1 fi -# If Carbon mod is installed, run enviroment.sh +# If Carbon mod is installed, run environment.sh if [ -f "${serverfiles}/carbon/tools/environment.sh" ]; then fn_print_info_nl "Running Carbon environment.sh" fn_script_log_info "Running Carbon environment.sh" diff --git a/lgsm/modules/fix_rw.sh b/lgsm/modules/fix_rw.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_samp.sh b/lgsm/modules/fix_samp.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_sdtd.sh b/lgsm/modules/fix_sdtd.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_sfc.sh b/lgsm/modules/fix_sfc.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_sm.sh b/lgsm/modules/fix_sm.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_sof2.sh b/lgsm/modules/fix_sof2.sh old mode 100644 new mode 100755 index 45e3b299c..3eb95bc9f --- a/lgsm/modules/fix_sof2.sh +++ b/lgsm/modules/fix_sof2.sh @@ -1,5 +1,5 @@ #!/bin/bash -# LinuxGSM fix_rust.sh module +# LinuxGSM fix_sof2.sh module # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com diff --git a/lgsm/modules/fix_squad.sh b/lgsm/modules/fix_squad.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_st.sh b/lgsm/modules/fix_st.sh old mode 100644 new mode 100755 index bbd9890bd..598d971b0 --- a/lgsm/modules/fix_st.sh +++ b/lgsm/modules/fix_st.sh @@ -1,5 +1,5 @@ #!/bin/bash -# LinuxGSM fix_rust.sh module +# LinuxGSM fix_ts.sh module # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com diff --git a/lgsm/modules/fix_steamcmd.sh b/lgsm/modules/fix_steamcmd.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_terraria.sh b/lgsm/modules/fix_terraria.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_tf2.sh b/lgsm/modules/fix_tf2.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_ts3.sh b/lgsm/modules/fix_ts3.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_unt.sh b/lgsm/modules/fix_unt.sh old mode 100644 new mode 100755 index dbe64ffd6..f32737285 --- a/lgsm/modules/fix_unt.sh +++ b/lgsm/modules/fix_unt.sh @@ -1,5 +1,5 @@ #!/bin/bash -# LinuxGSM fix_rust.sh module +# LinuxGSM fix_unt.sh module # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com diff --git a/lgsm/modules/fix_ut.sh b/lgsm/modules/fix_ut.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_ut2k4.sh b/lgsm/modules/fix_ut2k4.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_ut3.sh b/lgsm/modules/fix_ut3.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_vh.sh b/lgsm/modules/fix_vh.sh old mode 100644 new mode 100755 index 7c1455443..c6564eb19 --- a/lgsm/modules/fix_vh.sh +++ b/lgsm/modules/fix_vh.sh @@ -1,5 +1,5 @@ #!/bin/bash -# LinuxGSM fix_rust.sh module +# LinuxGSM fix_vh.sh module # Author: Alasdair Haig # Website: https://linuxgsm.com # Description: Resolves issues with Valheim. @@ -21,8 +21,8 @@ if [ -f "${modsinstalledlistfullpath}" ]; then rm -rf "${serverfiles}/unstripped_corlib" fi sed -i "s/^dllSearchPathOverride=unstripped_corlib/# &/" "${serverfiles}/doorstop_config.ini" - sed -i "s/^export DOORSTOP_CORLIB_OVERRIDE_PATH="$BASEDIR\/unstripped_corlib"/# &/" "${serverfiles}/start_game_bepinex.sh" - sed -i "s/^export DOORSTOP_CORLIB_OVERRIDE_PATH="${VALHEIM_PLUS_PATH}\/unstripped_corlib"/# &/" "${serverfiles}/start_server_bepinex.sh" + sed -i "s|^export DOORSTOP_CORLIB_OVERRIDE_PATH=\"\\\$BASEDIR/unstripped_corlib\"|# &|" "${serverfiles}/start_game_bepinex.sh" + sed -i "s|^export DOORSTOP_CORLIB_OVERRIDE_PATH=\"\\\${VALHEIM_PLUS_PATH}/unstripped_corlib\"|# &|" "${serverfiles}/start_server_bepinex.sh" fi # special exports for BepInEx if installed if grep -qE "^bepinexvh" "${modsinstalledlistfullpath}"; then diff --git a/lgsm/modules/fix_wurm.sh b/lgsm/modules/fix_wurm.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_xnt.sh b/lgsm/modules/fix_xnt.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/fix_zmr.sh b/lgsm/modules/fix_zmr.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/info_distro.sh b/lgsm/modules/info_distro.sh old mode 100644 new mode 100755 index a986edf1f..1d74ac635 --- a/lgsm/modules/info_distro.sh +++ b/lgsm/modules/info_distro.sh @@ -3,7 +3,7 @@ # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com -# Description: Variables providing useful info on the Operating System such as disk and performace info. +# Description: Variables providing useful info on the Operating System such as disk and performance info. # Used for command_details.sh, command_debug.sh and alert.sh. # !Note: When adding variables to this script, ensure that they are also added to the command_dev_parse_distro_details.sh script. @@ -13,9 +13,9 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" if [ "${status}" == "1" ]; then gameserverpid="$(tmux -L "${socketname}" list-sessions -F "#{session_name} #{pane_pid}" | grep "^${sessionname} " | awk '{print $NF}')" if [ "${engine}" == "source" ]; then - srcdslinuxpid="$(ps -ef | grep -v grep | grep "${gameserverpid}" | grep srcds_linux | awk '{print $2}')" + srcdslinuxpid="$(pgrep -P "${gameserverpid}" -x srcds_linux 2> /dev/null | head -n 1)" elif [ "${engine}" == "goldsrc" ]; then - hldslinuxpid="$(ps -ef | grep -v grep | grep "${gameserverpid}" | grep hlds_linux | awk '{print $2}')" + hldslinuxpid="$(pgrep -P "${gameserverpid}" -x hlds_linux 2> /dev/null | head -n 1)" fi fi ### Distro information @@ -252,11 +252,11 @@ if [ -d "${backupdir}" ]; then backupcount=0 # If there are backups in backup dir. - if [ "$(find "${backupdir}" -name "*.tar.*" | wc -l)" -ne "0" ]; then + if [ "$(find "${backupdir}" -maxdepth 1 -type f -name "*.tar.*" | wc -l)" -ne "0" ]; then # number of backups. - backupcount="$(find "${backupdir}"/*.tar.* | wc -l)" # integer + backupcount="$(find "${backupdir}" -maxdepth 1 -type f -name "*.tar.*" | wc -l)" # integer # most recent backup. - lastbackup="$(ls -1t "${backupdir}"/*.tar.* | head -1)" # string + lastbackup="$(find "${backupdir}" -maxdepth 1 -type f -name "*.tar.*" -printf '%T@ %p\n' 2> /dev/null | sort -nr | head -n 1 | cut -d' ' -f2-)" # string # date of most recent backup. lastbackupdate="$(date -r "${lastbackup}")" # string # no of days since last backup. @@ -272,7 +272,7 @@ netlink=$(${ethtoolcommand} "${netint}" 2> /dev/null | grep Speed | awk '{print # Sets the SteamCMD glibc requirement if the game server requirement is less or not required. if [ "${appid}" ]; then - if [ "${glibc}" = "null" ] || [ -z "${glibc}" ] || [ "$(printf '%s\n'${glibc}'\n' "2.14" | sort -V | head -n 1)" != "2.14" ]; then + if [ "${glibc}" = "null" ] || [ -z "${glibc}" ] || [ "$(printf '%s\n' "${glibc}" "2.14" | sort -V | head -n 1)" != "2.14" ]; then glibc="2.14" fi fi diff --git a/lgsm/modules/info_game.sh b/lgsm/modules/info_game.sh old mode 100644 new mode 100755 index 0b43ba626..d39e2d143 --- a/lgsm/modules/info_game.sh +++ b/lgsm/modules/info_game.sh @@ -350,7 +350,7 @@ fn_info_game_av() { rconenabled="${rconenabled:-"false"}" rconpassword="${rconpassword:-"NOT SET"}" rconport="${rconport:-"0"}" - # queryport doesnt respond to any queries, using session only. + # queryport doesn't respond to any queries, using session only. queryport=""$((port + 3))"" servername="${servername:-"NOT SET"}" serverpassword="${serverpassword:-"NOT SET"}" @@ -2514,7 +2514,7 @@ if [ ! -f "${tmpdir}/publicip.json" ] || [ "$(find "${tmpdir}/publicip.json" -mm ipresponse=$(curl -s --max-time 3 "${apiurl}") # Attempt to query ip-api.com with a 3 second timeout exitcode=$? - # Check if the first request was successfull + # Check if the first request was successful if [ "${exitcode}" -eq 0 ]; then fn_script_log_pass "Queried ${apiurl} for public IP address" @@ -2532,7 +2532,7 @@ if [ ! -f "${tmpdir}/publicip.json" ] || [ "$(find "${tmpdir}/publicip.json" -mm ipresponse=$(curl -s --max-time 3 "${apiurl}") # Attempt to query myip.wtf with a 3 second timeout as a backup exitcode=$? - # Check if the backup request was successfull + # Check if the backup request was successful if [ "${exitcode}" -eq 0 ]; then fn_script_log_pass "Queried ${apiurl} for public IP address" diff --git a/lgsm/modules/info_messages.sh b/lgsm/modules/info_messages.sh old mode 100644 new mode 100755 index 242c6b337..1ef950830 --- a/lgsm/modules/info_messages.sh +++ b/lgsm/modules/info_messages.sh @@ -369,7 +369,7 @@ fn_info_messages_gameserver() { fi fi - # Reverved Slots + # Reserved Slots if [ -n "${statspassword}" ]; then echo -e "${lightblue}Reserved Slots:\t${default}${reservedslots}" fi @@ -578,7 +578,7 @@ fn_info_messages_script() { : elif [ -z "${glibc}" ]; then echo -e "${lightblue}glibc required:\t${red}UNKNOWN${default}" - elif [ "$(printf '%s\n'${glibc}'\n' ${glibcversion} | sort -V | head -n 1)" != "${glibc}" ]; then + elif [ "$(printf '%s\n' "${glibc}" "${glibcversion}" | sort -V | head -n 1)" != "${glibc}" ]; then echo -e "${lightblue}glibc required:\t${red}${glibc} ${default}(${red}distro glibc ${glibcversion} too old${default})" else echo -e "${lightblue}glibc required:\t${green}${glibc}${default}" @@ -598,7 +598,7 @@ fn_info_messages_script() { echo -e "${lightblue}Gotify alert:\t${default}${gotifyalert}" fi # IFTTT alert - if [ "${iftttalert}" == "on" ]; then + if [ "${iftttalert}" == "on" ]; then echo -e "${lightblue}IFTTT alert:\t${default}${iftttalert}" fi # Pushbullet alert diff --git a/lgsm/modules/info_stats.sh b/lgsm/modules/info_stats.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_complete.sh b/lgsm/modules/install_complete.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh old mode 100644 new mode 100755 index b73e7b4b2..41d4ad866 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -16,7 +16,7 @@ fn_check_cfgdir() { fi } -# Copys default configs from Game-Server-Configs repo to server config location. +# Copies default configs from Game-Server-Configs repo to server config location. fn_default_config_remote() { echo -e "" echo -e "${bold}${lightyellow}Downloading ${gamename} Configs${default}" @@ -88,7 +88,7 @@ fn_default_config_remote() { done } -# Copys local default config to server config location. +# Copies local default config to server config location. fn_default_config_local() { echo -e "" echo -e "${bold}${lightyellow}Copying ${gamename} Configs${default}" diff --git a/lgsm/modules/install_dst_token.sh b/lgsm/modules/install_dst_token.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_eula.sh b/lgsm/modules/install_eula.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_factorio_save.sh b/lgsm/modules/install_factorio_save.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_gslt.sh b/lgsm/modules/install_gslt.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_header.sh b/lgsm/modules/install_header.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_logs.sh b/lgsm/modules/install_logs.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_mta_resources.sh b/lgsm/modules/install_mta_resources.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_retry.sh b/lgsm/modules/install_retry.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_server_dir.sh b/lgsm/modules/install_server_dir.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_squad_license.sh b/lgsm/modules/install_squad_license.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_stats.sh b/lgsm/modules/install_stats.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_steamcmd.sh b/lgsm/modules/install_steamcmd.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_ts3db.sh b/lgsm/modules/install_ts3db.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/install_ut2k4_key.sh b/lgsm/modules/install_ut2k4_key.sh old mode 100644 new mode 100755 index 963a52f10..4c62422d0 --- a/lgsm/modules/install_ut2k4_key.sh +++ b/lgsm/modules/install_ut2k4_key.sh @@ -18,7 +18,7 @@ if [ -z "${autoinstall}" ]; then echo -e "Once you have the key enter it below" echo -n "KEY: " read -r CODE - echo -e ""\""CDKey"\""="\""${CODE}"\""" > "${systemdir}/cdkey" + printf '"CDKey"="%s"\n' "${CODE}" > "${systemdir}/cdkey" if [ -f "${systemdir}/cdkey" ]; then fn_script_log_info "UT2K4 Server CD Key created" fi diff --git a/lgsm/modules/mods_core.sh b/lgsm/modules/mods_core.sh old mode 100644 new mode 100755 index b88e0c05e..bed0f9f49 --- a/lgsm/modules/mods_core.sh +++ b/lgsm/modules/mods_core.sh @@ -197,14 +197,15 @@ fn_mod_get_info() { # Variable to know when job is done. modinfocommand="0" # Find entry in global array. - for ((index = 0; index <= ${#mods_global_array[@]}; index++)); do + for ((index = 0; index < ${#mods_global_array[@]}; index++)); do # When entry is found. if [ "${mods_global_array[index]}" == "${currentmod}" ]; then # Go back to the previous "MOD" separator. - for ((index = index; index <= ${#mods_global_array[@]}; index--)); do + for ((index_search = index; index_search >= 0; index_search--)); do # When "MOD" is found. - if [ "${mods_global_array[index]}" == "MOD" ]; then + if [ "${mods_global_array[index_search]}" == "MOD" ]; then # Get info. + index=${index_search} fn_mods_define modinfocommand="1" break @@ -249,7 +250,7 @@ fn_mods_define() { } # Builds list of installed mods. -# using installed-mods.txt grabing mod info from mods_list.sh. +# using installed-mods.txt grabbing mod info from mods_list.sh. fn_mods_installed_list() { fn_mods_count_installed # Set/reset variables. @@ -331,7 +332,7 @@ fn_compatible_mod_engines() { # How many engines we need to test. enginesamount=$(echo -e "${modengines}" | awk -F ';' '{ print NF }') # Test all subvalue of "modengines" using the ";" separator. - for ((gamevarindex = 1; gamevarindex < ${enginesamount}; gamevarindex++)); do + for ((gamevarindex = 1; gamevarindex < enginesamount; gamevarindex++)); do # Put current engine name into modtest variable. enginemodtest=$(echo -e "${modengines}" | awk -F ';' -v x=${gamevarindex} '{ print $x }') # If engine name matches. @@ -472,7 +473,7 @@ fn_mods_check_installed() { # Count installed mods. fn_mods_count_installed # If no mods are found. - if [ ${installedmodscount} -eq 0 ]; then + if [ "${installedmodscount}" -eq 0 ]; then echo -e "" fn_print_failure_nl "No installed mods or addons were found" echo -e " * Install mods using LinuxGSM first with: ./${selfname} mods-install" @@ -566,7 +567,7 @@ fn_mod_liblist_gam_filenames() { esac } -# modifers for liblist.gam to add/remote metamod binaries +# modifiers for liblist.gam to add/remote metamod binaries fn_mod_install_liblist_gam_file() { fn_mod_liblist_gam_filenames @@ -689,13 +690,9 @@ fn_mod_install_amxmodx_file() { # since it does exist, is the entry already in plugins.ini logentry="line (linux addons/amxmodx/dlls/amxmodx_mm_i386.so) inserted into ${modinstalldir}/addons/metamod/plugins.ini" echo -en "adding amxmodx_mm_i386.so in plugins.ini..." - grep -q "amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then + if ! grep -q "amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"; then # file exists but the entry does not, let's add it - echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" >> "${modinstalldir}/addons/metamod/plugins.ini" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then + if ! echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" >> "${modinstalldir}/addons/metamod/plugins.ini"; then fn_script_log_fail "${logentry}" fn_print_fail_eol_nl else @@ -705,9 +702,7 @@ fn_mod_install_amxmodx_file() { fi else # create new file and add the mod to it - echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" > "${modinstalldir}/addons/metamod/plugins.ini" - exitcode=$? - if [ "${exitcode}" -ne 0 ]; then + if ! echo "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" > "${modinstalldir}/addons/metamod/plugins.ini"; then fn_script_log_fail "${logentry}" fn_print_fail_eol_nl core_exit.sh @@ -723,10 +718,8 @@ fn_mod_remove_amxmodx_file() { # since it does exist, is the entry already in plugins.ini logentry="line (linux addons/amxmodx/dlls/amxmodx_mm_i386.so) removed from ${modinstalldir}/addons/metamod/plugins.ini" echo -en "removing amxmodx_mm_i386.so in plugins.ini..." - grep -q "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini" - # iIs it found? If so remove it and clean up - exitcode=$? - if [ "${exitcode}" -eq 0 ]; then + # is it found? If so remove it and clean up + if grep -q "linux addons/amxmodx/dlls/amxmodx_mm_i386.so" "${modinstalldir}/addons/metamod/plugins.ini"; then # delete the line we inserted sed -i '/linux addons\/amxmodx\/dlls\/amxmodx_mm_i386.so/d' "${modinstalldir}/addons/metamod/plugins.ini" # remove empty lines diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh old mode 100644 new mode 100755 index bbefc5ea2..b3f9877f1 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -129,7 +129,7 @@ modseparator="MOD" # [9] | "Supported Engines;": list them according to LGSM ${engine} variables, separated and ended with a semicolon, or use ENGINES to ignore the value # [10] | "Supported Games;": list them according to LGSM ${gamename} variables, separated and ended with a semicolon, or use GAMES to ignore the value # [11] | "Unsupported Games;": list them according to LGSM ${gamename} variables, separated and ended with a semicolon, or use NOTGAMES to ignore the value (useful to exclude a game when using Supported Engines) -# [12] | "AUTHOR_URL" is the author's website, displayed to the user when chosing mods to install +# [12] | "AUTHOR_URL" is the author's website, displayed to the user when choosing mods to install # [13] | "Short Description" a description showed to the user upon installation/removal # Half-life 1 Engine Mods @@ -172,7 +172,7 @@ mod_info_ulib=(MOD "ulib" "ULib" "https://codeload.github.com/TeamUlysses/ulib/z mod_info_ulx=(MOD "ulx" "ULX" "https://codeload.github.com/TeamUlysses/ulx/zip/master" "ulx-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "Admin Panel (requires ULib)") mod_info_utime=(MOD "utime" "UTime" "https://github.com/TeamUlysses/utime/archive/master.zip" "utime-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "Keep track of players play time") mod_info_uclip=(MOD "uclip" "UClip" "https://github.com/TeamUlysses/uclip/archive/master.zip" "uclip-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://ulyssesmod.net" "An alternative to noclip") -mod_info_acf=(MOD "acf" "Armoured Combat Framework" "https://github.com/nrlulz/ACF/archive/master.zip" "acf-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "acf-master/lua/acf/shared/guns;" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/nrlulz/ACF" "Realistic Wepons & Engines") +mod_info_acf=(MOD "acf" "Armoured Combat Framework" "https://github.com/nrlulz/ACF/archive/master.zip" "acf-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "acf-master/lua/acf/shared/guns;" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/nrlulz/ACF" "Realistic Weapons & Engines") mod_info_acf_missiles=(MOD "acfmissiles" "ACF Missiles" "https://github.com/Bubbus/ACF-Missiles/archive/master.zip" "acf-missiles-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Bubbus/ACF-Missiles" "More missiles for ACF") mod_info_advdupe2=(MOD "advdupe2" "Advanced Duplicator 2" "https://github.com/wiremod/advdupe2/archive/master.zip" "advdupe2-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://www.wiremod.com" "Save your constructions. Second version") mod_info_pac3=(MOD "pac3" "PAC3" "https://github.com/CapsAdmin/pac3/archive/master.zip" "pac3-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/CapsAdmin/pac3" "Advanced player model customization") @@ -191,7 +191,7 @@ mod_info_magneticdipole=(MOD "magneticdipole" "Magnetic Dipole" "https://github. mod_info_environmentorganizer=(MOD "environmentorganizer" "Environment Organizer" "https://github.com/dvdvideo1234/environmentorganizer/archive/master.zip" "environmentorganizer-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/dvdvideo1234/EnvironmentOrganizer" "Installs routines designed for server settings adjustment") mod_info_improved_stacker=(MOD "improved-stacker" "Improved Stacker" "https://github.com/Mista-Tea/improved-stacker/archive/master.zip" "improved-stacker-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-stacker" "Stacks entities in the direction chosen") mod_info_improved_weight=(MOD "improved-weight" "Improved Weight" "https://github.com/Mista-Tea/improved-weight/archive/master.zip" "improved-weight-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-weight" "Weight tool but with more features") -mod_info_improved_antinoclip=(MOD "improved-antinoclip" "Improved Antinoclip" "https://github.com/Mista-Tea/improved-antinoclip/archive/master.zip" "improved-antinoclip-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-antinoclip" "Controls clipping trough an object") +mod_info_improved_antinoclip=(MOD "improved-antinoclip" "Improved Antinoclip" "https://github.com/Mista-Tea/improved-antinoclip/archive/master.zip" "improved-antinoclip-master.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/Mista-Tea/improved-antinoclip" "Controls clipping through an object") mod_info_darkrp=(MOD "darkrp" "DarkRP" "https://github.com/FPtje/DarkRP/archive/master.zip" "darkrp-master.zip" "0" "LowercaseOn" "${systemdir}/gamemodes" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://darkrp.com" "Most popular gamemode") mod_info_darkrpmodification=(MOD "darkrpmodification" "DarkRP Modification" "https://github.com/FPtje/darkrpmodification/archive/master.zip" "darkrpmodification-master.zip" "0" "LowercaseOff" "${systemdir}/addons" "NOUPDATE" "ENGINES" "Garry's Mod;" "NOTGAMES" "http://darkrp.com" "Customize DarkRP settings") mod_info_laserstool=(MOD "laserstool" "Laser STool" "https://github.com/dvdvideo1234/laserstool/archive/main.zip" "laserstool-main.zip" "0" "LowercaseOn" "${systemdir}/addons" "OVERWRITE" "ENGINES" "Garry's Mod;" "NOTGAMES" "https://github.com/dvdvideo1234/LaserSTool" "Scripted tool that spawns laser entities, simulates light rays and even kill players") diff --git a/lgsm/modules/query_gamedig.sh b/lgsm/modules/query_gamedig.sh old mode 100644 new mode 100755 index d8c3c6a7f..1fa74a823 --- a/lgsm/modules/query_gamedig.sh +++ b/lgsm/modules/query_gamedig.sh @@ -3,7 +3,7 @@ # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com -# Description: Querys a gameserver using node-gamedig. +# Description: Queries a gameserver using node-gamedig. # https://github.com/gamedig/node-gamedig moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" diff --git a/lgsm/modules/query_gsquery.py b/lgsm/modules/query_gsquery.py index 4dbde90dd..c4b8c3ddc 100644 --- a/lgsm/modules/query_gsquery.py +++ b/lgsm/modules/query_gsquery.py @@ -6,154 +6,206 @@ # Website: https://linuxgsm.com # Description: Allows querying of various game servers. +"""Query game servers using a set of lightweight UDP protocols.""" + import argparse import socket import sys -engine_types = ('protocol-valve', 'protocol-quake2', 'protocol-quake3', 'protocol-gamespy1', - 'protocol-unreal2', 'ut3', 'minecraft', 'minecraftbe', 'jc2m', 'mumbleping', 'soldat', 'teeworlds') +engine_types = ( + "protocol-valve", + "protocol-quake2", + "protocol-quake3", + "protocol-gamespy1", + "protocol-unreal2", + "ut3", + "minecraft", + "minecraftbe", + "jc2m", + "mumbleping", + "soldat", + "teeworlds", +) + +class GSQuery: + """Game server query dispatcher.""" -class gsquery: server_response_timeout = 2 default_buffer_length = 1024 - sourcequery = ('protocol-valve', 'avalanche3.0', 'barotrauma', 'madness', 'quakelive', 'realvirtuality', - 'refractor', 'source', 'goldsrc', 'spark', 'starbound', 'unity3d', 'unreal4', 'wurm') - idtech2query = ('protocol-quake2', 'idtech2', 'quake', 'iw2.0') - idtech3query = ('protocol-quake3', 'iw3.0', 'ioquake3', 'qfusion') - minecraftquery = ('minecraft', 'lwjgl2') - minecraftbequery = ('minecraftbe') - jc2mquery = ('jc2m') - mumblequery = ('mumbleping') - soldatquery = ('soldat') - twquery = ('teeworlds') - unrealquery = ('protocol-gamespy1', 'unreal') - unreal2query = ('protocol-unreal2', 'unreal2') - unreal3query = ('ut3', 'unreal3') + sourcequery = ( + "protocol-valve", + "avalanche3.0", + "barotrauma", + "madness", + "quakelive", + "realvirtuality", + "refractor", + "source", + "goldsrc", + "spark", + "starbound", + "unity3d", + "unreal4", + "wurm", + ) + idtech2query = ("protocol-quake2", "idtech2", "quake", "iw2.0") + idtech3query = ("protocol-quake3", "iw3.0", "ioquake3", "qfusion") + minecraftquery = ("minecraft", "lwjgl2") + minecraftbequery = ("minecraftbe",) + jc2mquery = ("jc2m",) + mumblequery = ("mumbleping",) + soldatquery = ("soldat",) + twquery = ("teeworlds",) + unrealquery = ("protocol-gamespy1", "unreal") + unreal2query = ("protocol-unreal2", "unreal2") + unreal3query = ("ut3", "unreal3") def __init__(self, arguments): + """Create a query instance from parsed CLI args.""" + self.argument = arguments # if self.argument.engine in self.sourcequery: - self.query_prompt_string = b'\xFF\xFF\xFF\xFFTSource Engine Query\0' + self.query_prompt_string = b"\xff\xff\xff\xffTSource Engine Query\0" elif self.argument.engine in self.idtech2query: - self.query_prompt_string = b'\xff\xff\xff\xffstatus\x00' + self.query_prompt_string = b"\xff\xff\xff\xffstatus\x00" elif self.argument.engine in self.idtech3query: - self.query_prompt_string = b'\xff\xff\xff\xffgetstatus' + self.query_prompt_string = b"\xff\xff\xff\xffgetstatus" elif self.argument.engine in self.jc2mquery: - self.query_prompt_string = b'\xFE\xFD\x09\x10\x20\x30\x40' + self.query_prompt_string = b"\xfe\xfd\x09\x10\x20\x30\x40" elif self.argument.engine in self.minecraftquery: - self.query_prompt_string = b'\xFE\xFD\x09\x3d\x54\x1f\x93' + self.query_prompt_string = b"\xfe\xfd\x09\x3d\x54\x1f\x93" elif self.argument.engine in self.minecraftbequery: - self.query_prompt_string = b'\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78\x00\x00\x00\x00\x00\x00\x00\x00' + self.query_prompt_string = ( + b"\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00" + b"\xfe\xfe\xfe\xfe\xfd\xfd\xfd\xfd\x12\x34\x56\x78" + b"\x00\x00\x00\x00\x00\x00\x00\x00" + ) elif self.argument.engine in self.mumblequery: - self.query_prompt_string = b'\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08' + self.query_prompt_string = ( + b"\x00\x00\x00\x00\x01\x02\x03\x04\x05\x06\x07\x08" + ) elif self.argument.engine in self.soldatquery: - self.query_prompt_string = b'\x69\x00' + self.query_prompt_string = b"\x69\x00" elif self.argument.engine in self.twquery: - self.query_prompt_string = b'\x04\x00\x00\xff\xff\xff\xff\x05' + \ - bytearray(511) + self.query_prompt_string = b"\x04\x00\x00\xff\xff\xff\xff\x05" + bytearray( + 511 + ) elif self.argument.engine in self.unrealquery: - self.query_prompt_string = b'\x5C\x69\x6E\x66\x6F\x5C' + self.query_prompt_string = b"\x5c\x69\x6e\x66\x6f\x5c" elif self.argument.engine in self.unreal2query: - self.query_prompt_string = b'\x79\x00\x00\x00\x00' + self.query_prompt_string = b"\x79\x00\x00\x00\x00" elif self.argument.engine in self.unreal3query: - self.query_prompt_string = b'\xFE\xFD\x09\x00\x00\x00\x00' + self.query_prompt_string = b"\xfe\xfd\x09\x00\x00\x00\x00" self.connected = False self.response = None @staticmethod def fatal_error(error_message, error_code=1): - sys.stderr.write('ERROR: ' + str(error_message) + '\n') + """Write an error message to stderr and exit.""" + + sys.stderr.write("ERROR: " + str(error_message) + "\n") sys.exit(error_code) @staticmethod - def exit_success(success_message=''): - sys.stdout.write('OK: ' + str(success_message) + '\n') + def exit_success(success_message=""): + """Write a success message to stdout and exit.""" + + sys.stdout.write("OK: " + str(success_message) + "\n") sys.exit(0) def responding(self): + """Send a single UDP query and print the response.""" + # Connect. connection = socket.socket(socket.AF_INET, socket.SOCK_DGRAM) connection.settimeout(self.server_response_timeout) try: self.connected = connection.connect( - (self.argument.address, int(self.argument.port))) + (self.argument.address, int(self.argument.port)) + ) except socket.timeout: - self.fatal_error('Request timed out', 1) - except Exception: - self.fatal_error('Unable to connect', 1) + self.fatal_error("Request timed out", 1) + except OSError: + self.fatal_error("Unable to connect", 1) # Send. connection.send(self.query_prompt_string) # Receive. try: self.response = connection.recv(self.default_buffer_length) except socket.error: - self.fatal_error('Unable to receive', 2) + self.fatal_error("Unable to receive", 2) connection.close() # Response. if self.response is None: - self.fatal_error('No response', 3) + self.fatal_error("No response", 3) if len(self.response) < 5: - sys.exit('Short response.', 3) + sys.exit("Short response.", 3) else: self.exit_success(str(self.response)) def parse_args(): + """Parse command-line arguments.""" + parser = argparse.ArgumentParser( - description='Allows querying of various game servers.', - usage='usage: python3 %(prog)s [options]', - add_help=False + description="Allows querying of various game servers.", + usage="usage: python3 %(prog)s [options]", + add_help=False, ) parser.add_argument( - '-a', '--address', + "-a", + "--address", type=str, required=True, - help='The IPv4 address of the server.' + help="The IPv4 address of the server.", ) parser.add_argument( - '-p', '--port', + "-p", + "--port", type=int, required=True, - help='The IPv4 port of the server.' + help="The IPv4 port of the server.", ) parser.add_argument( - '-e', '--engine', - metavar='ENGINE', + "-e", + "--engine", + metavar="ENGINE", choices=engine_types, - help='Engine type: ' + ' '.join(engine_types) + help="Engine type: " + " ".join(engine_types), ) parser.add_argument( - '-v', '--verbose', - action='store_true', - help='Display verbose output.' + "-v", + "--verbose", + action="store_true", + help="Display verbose output.", ) parser.add_argument( - '-d', '--debug', - action='store_true', - help='Display debugging output.' + "-d", + "--debug", + action="store_true", + help="Display debugging output.", ) parser.add_argument( - '-V', '--version', - action='version', - version='%(prog)s 0.0.1', - help='Display version and exit.' - ) - parser.add_argument( - '-h', '--help', - action='help', - help='Display help and exit.' + "-V", + "--version", + action="version", + version="%(prog)s 0.0.1", + help="Display version and exit.", ) + parser.add_argument("-h", "--help", action="help", help="Display help and exit.") return parser.parse_args() def main(): + """CLI entrypoint.""" + arguments = parse_args() - server = gsquery(arguments) + server = GSQuery(arguments) server.responding() -if __name__ == '__main__': +if __name__ == "__main__": main() diff --git a/lgsm/modules/update_fctr.sh b/lgsm/modules/update_fctr.sh old mode 100644 new mode 100755 index 3418c7424..5de789cdb --- a/lgsm/modules/update_fctr.sh +++ b/lgsm/modules/update_fctr.sh @@ -10,25 +10,32 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_update_dl() { # Download and extract files to serverfiles. fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "nohash" - fn_dl_extract "${tmpdir}" "factorio_headless_${factorioarch}-${remotebuildversion}.tar.xz" "${serverfiles}" "factorio" + fn_dl_extract "${tmpdir}" "factorio_headless_${factorioarch}-${remotebuild}.tar.xz" "${serverfiles}" "factorio" fn_clear_tmp } fn_update_localbuild() { - # Gets local build info. - fn_print_dots "Checking local build: ${remotelocation}" + # Optional arg1: 'silent' to suppress user-facing output + local mode="${1:-}" + if [ "${mode}" != "silent" ]; then + fn_print_dots "Checking local build: ${remotelocation}" + fi # Uses executable to get local build. if [ -d "${executabledir}" ]; then cd "${executabledir}" || exit localbuild=$(${executable} --version | grep -m 1 "Version:" | awk '{print $2}') fi if [ -z "${localbuild}" ]; then - fn_print_error "Checking local build: ${remotelocation}: missing local build info" + if [ "${mode}" != "silent" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + fi fn_script_log_error "Missing local build info" fn_script_log_error "Set localbuild to 0" localbuild="0" else - fn_print_ok "Checking local build: ${remotelocation}" + if [ "${mode}" != "silent" ]; then + fn_print_ok "Checking local build: ${remotelocation}" + fi fn_script_log_pass "Checking local build" fi } @@ -37,14 +44,14 @@ fn_update_remotebuild() { # Gets remote build info. apiurl="https://factorio.com/get-download/${branch}/headless/${factorioarch}" remotebuildresponse=$(curl -s "${apiurl}") - remotebuildversion=$(echo "${remotebuildresponse}" | grep -o '[0-9]\.[0-9]\{1,\}\.[0-9]\{1,\}' | head -1) + remotebuild=$(echo "${remotebuildresponse}" | grep -o '[0-9]\.[0-9]\{1,\}\.[0-9]\{1,\}' | head -1) remotebuildurl="https://factorio.com/get-download/${branch}/headless/${factorioarch}" - remotebuildfilename="factorio_headless_${factorioarch}-${remotebuildversion}.tar.xz" + remotebuildfilename="factorio_headless_${factorioarch}-${remotebuild}.tar.xz" if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -54,7 +61,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -65,35 +72,37 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild} ${factorioarch}${default}" - echo -e "* Remote build: ${green}${remotebuildversion} ${factorioarch}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild} ${factorioarch}" - fn_script_log_info "Remote build: ${remotebuildversion} ${factorioarch}" + fn_script_log_info "Remote build: ${remotebuild} ${factorioarch}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + # Keep track of the build before updating for alert purposes. + previousbuild="${localbuild}" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -120,6 +129,23 @@ fn_update_compare() { command_start.sh fn_firstcommand_reset fi + # Refresh local build value after update (silent) so alerts show new version. + fn_update_localbuild silent + # Verify the update applied correctly unless forced update to same version. + if [ "${localbuild}" != "${remotebuild}" ]; then + # If forced update and version unchanged treat as acceptable; otherwise failure. + if [ "${forceupdate}" != "1" ] || [ "${previousbuild}" = "${localbuild}" ]; then + fn_script_log_error "Update verification failed: expected ${remotebuild}, got ${localbuild}" + fn_print_fail_nl "Update verification failed: expected ${remotebuild}, got ${localbuild}" + updatefailureexpected="${remotebuild}" + updatefailuregot="${localbuild}" + alert="update-failed" + alert.sh + core_exit.sh + fi + else + fn_script_log_pass "Update verification success: ${previousbuild} -> ${localbuild}" + fi unset exitbypass alert="update" elif [ "${commandname}" == "CHECK-UPDATE" ]; then @@ -128,26 +154,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild} ${factorioarch}${default}" - echo -e "* Remote build: ${green}${remotebuildversion} ${factorioarch}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild} ${factorioarch}" - fn_script_log_info "Remote build: ${remotebuildversion} ${factorioarch}" + fn_script_log_info "Remote build: ${remotebuild} ${factorioarch}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } diff --git a/lgsm/modules/update_jk2.sh b/lgsm/modules/update_jk2.sh old mode 100644 new mode 100755 index 5fdd54c65..ee40988d9 --- a/lgsm/modules/update_jk2.sh +++ b/lgsm/modules/update_jk2.sh @@ -36,12 +36,12 @@ fn_update_remotebuild() { remotebuildresponse=$(curl -s "${apiurl}") remotebuildfilename=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("dedicated.zip")) | .name') remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("dedicated.zip")) | .browser_download_url') - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.tag_name') + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name') if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -51,7 +51,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -62,34 +62,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -117,7 +118,6 @@ fn_update_compare() { fn_firstcommand_reset fi unset exitbypass - date +%s > "${lockdir}/last-updated.lock" alert="update" elif [ "${commandname}" == "CHECK-UPDATE" ]; then alert="check-update" @@ -125,26 +125,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -152,12 +152,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="github.com" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/lgsm/modules/update_mc.sh b/lgsm/modules/update_mc.sh old mode 100644 new mode 100755 index a9be77576..81540f002 --- a/lgsm/modules/update_mc.sh +++ b/lgsm/modules/update_mc.sh @@ -39,24 +39,24 @@ fn_update_remotebuild() { remotebuildresponse=$(curl -s "${apiurl}") # Latest release. if [ "${branch}" == "release" ] && [ "${mcversion}" == "latest" ]; then - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.latest.release') + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.latest.release') # Latest snapshot. elif [ "${branch}" == "snapshot" ] && [ "${mcversion}" == "latest" ]; then - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.latest.snapshot') + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.latest.snapshot') # Specific release/snapshot. else - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${mcversion}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .id') + remotebuild=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${mcversion}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .id') fi - remotebuildfilename="minecraft_server.${remotebuildversion}.jar" + remotebuildfilename="minecraft_server.${remotebuild}.jar" # Generate link to version manifest json. - remotebuildmanifest=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${remotebuildversion}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .url') + remotebuildmanifest=$(echo "${remotebuildresponse}" | jq -r --arg branch "${branch}" --arg mcversion "${remotebuild}" '.versions | .[] | select(.type==$branch and .id==$mcversion) | .url') # Generate link to server.jar remotebuildurl=$(curl -s "${remotebuildmanifest}" | jq -r '.downloads.server.url') if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -66,7 +66,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -77,35 +77,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -140,26 +140,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -167,12 +167,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="mojang.com" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/lgsm/modules/update_mcb.sh b/lgsm/modules/update_mcb.sh old mode 100644 new mode 100755 index a8616c3b8..9940415a1 --- a/lgsm/modules/update_mcb.sh +++ b/lgsm/modules/update_mcb.sh @@ -8,12 +8,12 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_update_dl() { - fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "bedrock_server.${remotebuildversion}.zip" "nochmodx" "norun" "noforce" "nohash" + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "bedrock_server.${remotebuild}.zip" "nochmodx" "norun" "noforce" "nohash" echo -e "Extracting to ${serverfiles}...\c" if [ "${firstcommandname}" == "INSTALL" ]; then - unzip -oq "${tmpdir}/bedrock_server.${remotebuildversion}.zip" -x "server.properties" -d "${serverfiles}" + unzip -oq "${tmpdir}/bedrock_server.${remotebuild}.zip" -x "server.properties" -d "${serverfiles}" else - unzip -oq "${tmpdir}/bedrock_server.${remotebuildversion}.zip" -x "permissions.json" "server.properties" "allowlist.json" -d "${serverfiles}" + unzip -oq "${tmpdir}/bedrock_server.${remotebuild}.zip" -x "permissions.json" "server.properties" "allowlist.json" -d "${serverfiles}" fi exitcode=$? if [ "${exitcode}" -ne 0 ]; then @@ -61,13 +61,13 @@ fn_update_remotebuild() { else remotebuildurl=$(echo "${remotebuildresponse}" | jq -r 'select(.downloadType == "serverBedrockLinux") | .downloadUrl') fi - remotebuildversion=$(echo "${remotebuildurl}" | grep -Eo "[.0-9]+[0-9]") - remotebuildfilename="bedrock-server-${remotebuildversion}.zip" + remotebuild=$(echo "${remotebuildurl}" | grep -Eo "[.0-9]+[0-9]") + remotebuildfilename="bedrock-server-${remotebuild}.zip" if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -77,7 +77,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -88,35 +88,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -151,26 +151,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -178,12 +178,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="minecraft.net" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/lgsm/modules/update_mta.sh b/lgsm/modules/update_mta.sh old mode 100644 new mode 100755 index 50a3fb895..b1ba0459c --- a/lgsm/modules/update_mta.sh +++ b/lgsm/modules/update_mta.sh @@ -39,11 +39,11 @@ fn_update_remotebuild() { remotebuildresponse=$(curl -s "${apiurl}") remotebuildfilename="multitheftauto_linux_x64.tar.gz" remotebuildurl="http://linux.mtasa.com/dl/multitheftauto_linux_x64.tar.gz" - remotebuildversion=$(echo "${remotebuildresponse}") + remotebuild="${remotebuildresponse}" if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -53,7 +53,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -64,7 +64,7 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" if [ "${forceupdate}" == "1" ]; then @@ -74,30 +74,31 @@ fn_update_compare() { mtaupdatestatus="available" fi fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -125,7 +126,6 @@ fn_update_compare() { fn_firstcommand_reset fi unset exitbypass - date +%s > "${lockdir}/last-updated.lock" alert="update" elif [ "${commandname}" == "CHECK-UPDATE" ]; then alert="check-update" @@ -133,26 +133,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -160,12 +160,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="linux.mtasa.com" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/lgsm/modules/update_pmc.sh b/lgsm/modules/update_pmc.sh old mode 100644 new mode 100755 index c38911d4e..e0bbfa05a --- a/lgsm/modules/update_pmc.sh +++ b/lgsm/modules/update_pmc.sh @@ -11,7 +11,7 @@ fn_update_dl() { # Download and extract files to serverfiles. fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "chmodx" "norun" "force" "${remotebuildhash}" cp -f "${tmpdir}/${remotebuildfilename}" "${serverfiles}/${executable#./}" - echo "${remotebuildversion}" > "${serverfiles}/build.txt" + echo "${remotebuild}" > "${serverfiles}/build.txt" fn_clear_tmp } @@ -61,12 +61,12 @@ fn_update_remotebuild() { remotebuildhash=$(echo "${remotebuildresponseversion}" | jq -r '.downloads.application.sha256') remotebuildurl="${apiurl}/${paperproject}/versions/${remotebuildmcversion}/builds/${remotebuildpaperversion}/downloads/${remotebuildfilename}" # Combines Minecraft: Java Edition version and paper build. e.g 1.16.5-456 - remotebuildversion="${remotebuildmcversion}-${remotebuildpaperversion}" + remotebuild="${remotebuildmcversion}-${remotebuildpaperversion}" if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -76,7 +76,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -87,35 +87,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -150,26 +150,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -177,12 +177,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="papermc.io" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${shortname}" == "pmc" ]; then paperproject="paper" elif [ "${shortname}" == "vpmc" ]; then diff --git a/lgsm/modules/update_steamcmd.sh b/lgsm/modules/update_steamcmd.sh old mode 100644 new mode 100755 diff --git a/lgsm/modules/update_ts3.sh b/lgsm/modules/update_ts3.sh old mode 100644 new mode 100755 index e1917e5e1..ec3bc0060 --- a/lgsm/modules/update_ts3.sh +++ b/lgsm/modules/update_ts3.sh @@ -43,12 +43,12 @@ fn_update_remotebuild() { remotebuildhash=$(echo -e "${remotebuildresponse}" | jq -r '.linux.x86.checksum') fi remotebuildfilename=$(basename "${remotebuildurl}") - remotebuildversion=$(echo -e "${remotebuildresponse}" | jq -r '.linux.x86_64.version') + remotebuild=$(echo -e "${remotebuildresponse}" | jq -r '.linux.x86_64.version') if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -58,7 +58,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -69,35 +69,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -132,26 +132,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -171,12 +171,6 @@ fi # The location where the builds are checked and downloaded. remotelocation="teamspeak.com" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/lgsm/modules/update_ut99.sh b/lgsm/modules/update_ut99.sh old mode 100644 new mode 100755 index bdfb96f0b..4e3f93b31 --- a/lgsm/modules/update_ut99.sh +++ b/lgsm/modules/update_ut99.sh @@ -11,7 +11,7 @@ fn_update_dl() { # Download and extract files to serverfiles. fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "nohash" fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" - echo "${remotebuildversion}" > "${serverfiles}/build.txt" + echo "${remotebuild}" > "${serverfiles}/build.txt" fn_clear_tmp } @@ -37,12 +37,12 @@ fn_update_remotebuild() { remotebuildresponse=$(curl -s "${apiurl}") remotebuildfilename=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("Linux-amd64")) | .name') remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.assets[]|select(.browser_download_url | contains("Linux-amd64")) | .browser_download_url') - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '.tag_name') + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name') if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -52,7 +52,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -63,35 +63,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -126,26 +126,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -153,12 +153,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="github.com" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/lgsm/modules/update_vints.sh b/lgsm/modules/update_vints.sh old mode 100644 new mode 100755 index a300b87eb..86a7156ee --- a/lgsm/modules/update_vints.sh +++ b/lgsm/modules/update_vints.sh @@ -20,6 +20,7 @@ fn_update_localbuild() { # Uses executable to get local build. if [ -d "${executabledir}" ]; then cd "${executabledir}" || exit + # shellcheck disable=SC2086 # Intentional: preexecutable may be empty; unquoted to drop it without producing an empty arg. localbuild="$(${preexecutable} ${executable} --version 2> /dev/null | sed '/^[[:space:]]*$/d')" fi if [ -z "${localbuild}" ]; then @@ -44,14 +45,14 @@ fn_update_remotebuild() { else remotebuildversion="${branch}" fi - remotebuildfilename=$(echo "${remotebuildresponse}" | jq --arg remotebuildversion "${remotebuildversion}" -r '.[$remotebuildversion].linuxserver.filename') - remotebuildurl=$(echo "${remotebuildresponse}" | jq --arg remotebuildversion "${remotebuildversion}" -r '.[$remotebuildversion].linuxserver.urls.cdn') - remotebuildhash=$(echo "${remotebuildresponse}" | jq --arg remotebuildversion "${remotebuildversion}" -r '.[$remotebuildversion].linuxserver.md5') + remotebuildfilename=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.filename') + remotebuildurl=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.urls.cdn') + remotebuildhash=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.md5') if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -61,7 +62,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -72,35 +73,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -135,26 +136,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -162,12 +163,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="vintagestory.at" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/lgsm/modules/update_xnt.sh b/lgsm/modules/update_xnt.sh old mode 100644 new mode 100755 index c00233aa7..3a937a9f6 --- a/lgsm/modules/update_xnt.sh +++ b/lgsm/modules/update_xnt.sh @@ -54,13 +54,12 @@ fn_update_remotebuild() { remotebuildfilename=$(echo "${remotebuildtag}" | tr -d 'v') remotebuildfilename="${remotebuildfilename}.zip" remotebuildurl="https://dl.xonotic.org/${remotebuildfilename}" - - remotebuildversion="${remotebuildtag}" + remotebuild="${remotebuildtag}" if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" - # Checks if remotebuildversion variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_fail "Checking remote build: ${remotelocation}" fn_script_log_fail "Checking remote build" core_exit.sh @@ -70,7 +69,7 @@ fn_update_remotebuild() { fi else # Checks if remotebuild variable has been set. - if [ -z "${remotebuildversion}" ] || [ "${remotebuildversion}" == "null" ]; then + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then fn_print_failure "Unable to get remote build" fn_script_log_fail "Unable to get remote build" core_exit.sh @@ -81,35 +80,35 @@ fn_update_remotebuild() { fn_update_compare() { fn_print_dots "Checking for update: ${remotelocation}" # Update has been found or force update. - if [ "${localbuild}" != "${remotebuildversion}" ] || [ "${forceupdate}" == "1" ]; then + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then # Create update lockfile. date '+%s' > "${lockdir:?}/update.lock" fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "Update available" - echo -e "* Local build: ${red}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "Update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi - fn_script_log_info "${localbuild} > ${remotebuildversion}" + fn_script_log_info "${localbuild} > ${remotebuild}" if [ "${commandname}" == "UPDATE" ]; then - date +%s > "${lockdir}/last-updated.lock" + date +%s > "${lockdir:?}/last-updated.lock" unset updateonstart check_status.sh # If server stopped. @@ -144,26 +143,26 @@ fn_update_compare() { alert.sh else fn_print_ok_nl "Checking for update: ${remotelocation}" - echo -en "\n" - echo -e "No update available" - echo -e "* Local build: ${green}${localbuild}${default}" - echo -e "* Remote build: ${green}${remotebuildversion}${default}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" if [ -n "${branch}" ]; then - echo -e "* Branch: ${branch}" + fn_print_nl "* Branch: ${branch}" fi - echo -en "\n" + fn_print "\n" fn_script_log_info "No update available" fn_script_log_info "Local build: ${localbuild}" - fn_script_log_info "Remote build: ${remotebuildversion}" + fn_script_log_info "Remote build: ${remotebuild}" if [ -n "${branch}" ]; then fn_script_log_info "Branch: ${branch}" fi if [ -f "${rootdir}/.dev-debug" ]; then - echo -e "Remote build info" - echo -e "* apiurl: ${apiurl}" - echo -e "* remotebuildfilename: ${remotebuildfilename}" - echo -e "* remotebuildurl: ${remotebuildurl}" - echo -e "* remotebuildversion: ${remotebuildversion}" + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" fi fi } @@ -171,12 +170,6 @@ fn_update_compare() { # The location where the builds are checked and downloaded. remotelocation="github.com" -if [ ! "$(command -v jq 2> /dev/null)" ]; then - fn_print_fail_nl "jq is not installed" - fn_script_log_fail "jq is not installed" - core_exit.sh -fi - if [ "${firstcommandname}" == "INSTALL" ]; then fn_update_remotebuild fn_update_dl diff --git a/linuxgsm.sh b/linuxgsm.sh index 997bc30c8..443e1d8bf 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -330,7 +330,8 @@ fn_install_menu() { # Gets server info from serverlist.csv and puts in to array. fn_server_info() { IFS="," - server_info_array=($(grep -aw "${userinput}" "${serverlist}")) + server_info_line="$(grep -aw "${userinput}" "${serverlist}" | head -n 1)" + read -r -a server_info_array <<< "${server_info_line}" shortname="${server_info_array[0]}" # csgo gameservername="${server_info_array[1]}" # csgoserver gamename="${server_info_array[2]}" # Counter Strike: Global Offensive diff --git a/package.json b/package.json index 404356e5e..b9a348507 100644 --- a/package.json +++ b/package.json @@ -1,27 +1,27 @@ { - "name": "linuxgsm", - "description": "


\"LinuxGSM\"

", - "directories": { - "test": "tests" - }, - "devDependencies": { - "prettier": "^3.4.2", - "prettier-plugin-sh": "^0.14.0" - }, - "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" - }, - "repository": { - "type": "git", - "url": "git+https://github.com/GameServerManagers/LinuxGSM.git" - }, - "author": "", - "license": "MIT", - "bugs": { - "url": "https://github.com/GameServerManagers/LinuxGSM/issues" - }, - "homepage": "https://github.com/GameServerManagers/LinuxGSM#readme", - "dependencies": { - "gamedig": "^5.1.4" - } + "name": "linuxgsm", + "description": "


\"LinuxGSM\"

", + "directories": { + "test": "tests" + }, + "devDependencies": { + "prettier": "^3.4.2", + "prettier-plugin-sh": "^0.14.0" + }, + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/GameServerManagers/LinuxGSM.git" + }, + "author": "", + "license": "MIT", + "bugs": { + "url": "https://github.com/GameServerManagers/LinuxGSM/issues" + }, + "homepage": "https://github.com/GameServerManagers/LinuxGSM#readme", + "dependencies": { + "gamedig": "^5.1.4" + } } From 82b820879266736d879a64b082988900422390a8 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Thu, 12 Mar 2026 22:41:14 +0000 Subject: [PATCH 05/53] docs(license): update copyright year(s) (#4866) Co-authored-by: github-actions Co-authored-by: Daniel Gibbs --- LICENSE.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/LICENSE.md b/LICENSE.md index c8ab9fa34..c138f4071 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,6 +1,6 @@ # The MIT License (MIT) -Copyright (c) 2012-2025 Daniel Gibbs +Copyright (c) 2012-2026 Daniel Gibbs Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal From b930161f1dffa038c95dd002dad327f0de6bf1db Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 13 Mar 2026 21:10:17 +0000 Subject: [PATCH 06/53] fix: re-add missing module --- lgsm/modules/core_modules.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 2cc635888..b2bd522a8 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -451,6 +451,11 @@ fix_samp.sh() { fn_fetch_module } +fix_sdtd.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + fix_sfc.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module From 397f26e9bac2904067a6305535c44ae4bd36b40d Mon Sep 17 00:00:00 2001 From: Anton Siuvaev Date: Sun, 19 Apr 2026 01:41:21 +0300 Subject: [PATCH 07/53] Update papermc.io API usage to new format (#4895) Co-authored-by: Anton Siuvaev --- lgsm/modules/update_pmc.sh | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/lgsm/modules/update_pmc.sh b/lgsm/modules/update_pmc.sh index e0bbfa05a..9273a567a 100755 --- a/lgsm/modules/update_pmc.sh +++ b/lgsm/modules/update_pmc.sh @@ -32,18 +32,19 @@ fn_update_localbuild() { } fn_update_remotebuild() { + jq_versions_all='.versions | to_entries | map(.value[])' # Gets remote build info. - apiurl="https://api.papermc.io/v2/projects" + apiurl="https://fill.papermc.io/v3/projects" # Get list of projects. remotebuildresponse=$(curl -s "${apiurl}") # Get list of Minecraft versions for project. remotebuildresponseproject=$(curl -s "${apiurl}/${paperproject}") # Get latest Minecraft: Java Edition version or user specified version. if [ "${mcversion}" == "latest" ]; then - remotebuildmcversion=$(echo "${remotebuildresponseproject}" | jq -r '.versions[-1]') + remotebuildmcversion=$(echo "${remotebuildresponseproject}" | jq -r "$jq_versions_all | first") else # Checks if user specified version exists. - remotebuildmcversion=$(echo "${remotebuildresponseproject}" | jq -r -e --arg mcversion "${mcversion}" '.versions[]|select(. == $mcversion)') + remotebuildmcversion=$(echo "${remotebuildresponseproject}" | jq -r -e --arg mcversion "${mcversion}" "$jq_versions_all | .[] | select(. == \$mcversion)") if [ -z "${remotebuildmcversion}" ]; then # user passed version does not exist fn_print_error_nl "Version ${mcversion} not available from ${remotelocation}" @@ -54,12 +55,12 @@ fn_update_remotebuild() { # Get list of paper builds for specific Minecraft: Java Edition version. remotebuildresponsemcversion=$(curl -s "${apiurl}/${paperproject}/versions/${remotebuildmcversion}") # Get latest paper build for specific Minecraft: Java Edition version. - remotebuildpaperversion=$(echo "${remotebuildresponsemcversion}" | jq -r '.builds[-1]') + remotebuildpaperversion=$(echo "${remotebuildresponsemcversion}" | jq -r '.builds[0]') # Get various info about the paper build. remotebuildresponseversion=$(curl -s "${apiurl}/${paperproject}/versions/${remotebuildmcversion}/builds/${remotebuildpaperversion}") - remotebuildfilename=$(echo "${remotebuildresponseversion}" | jq -r '.downloads.application.name') - remotebuildhash=$(echo "${remotebuildresponseversion}" | jq -r '.downloads.application.sha256') - remotebuildurl="${apiurl}/${paperproject}/versions/${remotebuildmcversion}/builds/${remotebuildpaperversion}/downloads/${remotebuildfilename}" + remotebuildfilename=$(echo "${remotebuildresponseversion}" | jq -r '.downloads["server:default"].name') + remotebuildhash=$(echo "${remotebuildresponseversion}" | jq -r '.downloads["server:default"].checksums.sha256') + remotebuildurl=$(echo "${remotebuildresponseversion}" | jq -r '.downloads["server:default"].url') # Combines Minecraft: Java Edition version and paper build. e.g 1.16.5-456 remotebuild="${remotebuildmcversion}-${remotebuildpaperversion}" From f45456e32d687f9a43da7c87715d5ea9812db8eb Mon Sep 17 00:00:00 2001 From: Hugo Maurin <148004075+Huguiz@users.noreply.github.com> Date: Sun, 19 Apr 2026 00:45:40 +0200 Subject: [PATCH 09/53] fix(mcserver): update Ubuntu 24.04 Java dependency to OpenJDK 25 (#4890) Co-authored-by: Daniel Gibbs --- lgsm/data/ubuntu-24.04.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index d130d68c4..ff95bec14 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -65,7 +65,7 @@ kf kf2 l4d l4d2 -mc,openjdk-21-jre +mc,openjdk-25-jre mcb mh mohaa,libstdc++5:i386 From cba689ab4b60b958cae7a9fc61800e7d16058b8d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 11:12:51 +0100 Subject: [PATCH 11/53] feat(etl): add ET: Legacy downloader and update module (#4896) * feat(etl): add downloader and update support for ET: Legacy Refactors ET: Legacy to use a dedicated update module instead of hardcoded installation files. The new update_etl.sh module leverages the GitHub API to check for, download, and apply the latest builds from GameServerManagers/etlserver-build. * feat(etl): add update_etl module to core modules Registers the update_etl.sh module within the core modules to enable the fetching and execution of ET: Legacy updates. * feat(etl): add update commands to core_getopt Ensures that the update and check-update commands are available for ET: Legacy by including the etl shortname in the getopt command registration logic. * feat(etl): improve local build detection Updates the game log directory to the "legacy" folder and enhances local build detection by parsing etconsole.log for version information, falling back to build.txt if necessary. * feat(etl): update glibc requirement and log path detection Updates the minimum glibc requirement to 2.17 and switches the local build detection to use the gamelogdir variable instead of a hardcoded path. * feat(etl): improve MD5 hash extraction Updates the MD5 hash parsing to use a specific regex for 32-character hexadecimal strings, providing a more robust extraction from the release body than relying on the last field of the line. * feat(xnt): add SHA512 hash extraction for remote builds Updates the Xonotic update module to fetch the SHA512 hash from the remote download server, allowing for build verification and identification. * fix(xnt): derive sha512 URL from remotebuildfilename not remotebuildtag Tag format is xonotic-v0.8.6 but the sha512 file is named xonotic-0.8.6.sha512 (without the v). Using remotebuildtag directly produced a 404. Deriving from remotebuildfilename (which already has the v stripped by tr -d v) gives the correct URL. * fix(core_dl): fix zip extraction with extractsrc across devices and non-empty dirs Using mv to move extracted directories fails in two cases: - Cross-device moves (e.g. tmp and serverfiles on different Docker volumes) - Target directory already exists and is non-empty (update scenario) Replace find+mv with cp -a which handles both cases by copying recursively and merging into the destination. Also replace the hardcoded 'Xonotic' temp_extractdir with ${extractsrc} to be generic. * fix(core_dl): remove duplicate ellipsis in hash verification message --- .../config-lgsm/etlserver/_default.cfg | 4 +- lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_dl.sh | 6 +- lgsm/modules/core_getopt.sh | 2 +- lgsm/modules/core_modules.sh | 5 + lgsm/modules/install_server_files.sh | 10 +- lgsm/modules/update_etl.sh | 173 ++++++++++++++++++ lgsm/modules/update_xnt.sh | 1 + 9 files changed, 191 insertions(+), 14 deletions(-) create mode 100644 lgsm/modules/update_etl.sh diff --git a/lgsm/config-default/config-lgsm/etlserver/_default.cfg b/lgsm/config-default/config-lgsm/etlserver/_default.cfg index 04ebe4e23..9679a8f44 100644 --- a/lgsm/config-default/config-lgsm/etlserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/etlserver/_default.cfg @@ -141,7 +141,7 @@ consoleinteract="yes" # Do not edit gamename="ET: Legacy" engine="idtech3" -glibc="2.7" +glibc="2.17" #### Directories #### # Edit with care @@ -160,7 +160,7 @@ backupdir="${lgsmdir}/backup" ## Logging Directories [ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" -gamelogdir="${serverfiles}/Logs" +gamelogdir="${serverfiles}/legacy" lgsmlogdir="${logdir}/script" consolelogdir="${logdir}/console" lgsmlog="${lgsmlogdir}/${selfname}-script.log" diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 38f8b4ddc..6e429512a 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -34,6 +34,8 @@ elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then update_xnt.sh +elif [ "${shortname}" == "etl" ]; then + update_etl.sh else update_steamcmd.sh fi diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 6bb30a4c8..996d402a4 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -35,6 +35,8 @@ elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then update_xnt.sh +elif [ "${shortname}" == "etl" ]; then + update_etl.sh else update_steamcmd.sh fi diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 0a0dacb29..1c27c58d7 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -204,7 +204,7 @@ fn_dl_hash() { fn_print_error_nl "hash length not known for hash type" core_exit.sh fi - echo -en "verifying ${local_filename} with ${hashtype}..." + echo -en "verifying ${local_filename} with ${hashtype}" fn_sleep_time hashsumcmd=$(${hashbin} "${local_filedir}/${local_filename}" | awk '{print $1}') if [ "${hashsumcmd}" != "${hash}" ]; then @@ -267,9 +267,9 @@ fn_dl_extract() { fi elif [ "${mime}" == "application/zip" ]; then if [ -n "${extractsrc}" ]; then - temp_extractdir="${tmpdir}/Xonotic" + temp_extractdir="${tmpdir}/${extractsrc}" extractcmd=$(unzip -qo "${local_filedir}/${local_filename}" "${extractsrc}/*" -d "${temp_extractdir}") - find "${temp_extractdir}/${extractsrc}" -mindepth 1 -maxdepth 1 -exec mv -t "${extractdest}" {} + + cp -a "${temp_extractdir}/${extractsrc}/." "${extractdest}/" rm -rf "${temp_extractdir}" else extractcmd=$(unzip -qo -d "${extractdest}" "${local_filedir}/${local_filename}") diff --git a/lgsm/modules/core_getopt.sh b/lgsm/modules/core_getopt.sh index 295f9900b..ad09bf1df 100755 --- a/lgsm/modules/core_getopt.sh +++ b/lgsm/modules/core_getopt.sh @@ -66,7 +66,7 @@ currentopt=("${cmd_start[@]}" "${cmd_stop[@]}" "${cmd_restart[@]}" "${cmd_monito currentopt+=("${cmd_update_linuxgsm[@]}") # Exclude noupdate games here. -if [ "${shortname}" == "jk2" ] || [ "${engine}" != "idtech3" ]; then +if [ "${shortname}" == "jk2" ] || [ "${shortname}" == "etl" ] || [ "${engine}" != "idtech3" ]; then if [ "${shortname}" != "bf1942" ] && [ "${shortname}" != "bfv" ] && [ "${engine}" != "idtech2" ] && [ "${engine}" != "iw2.0" ] && [ "${engine}" != "iw3.0" ] && [ "${engine}" != "quake" ] && [ "${shortname}" != "samp" ] && [ "${shortname}" != "ut2k4" ]; then currentopt+=("${cmd_update[@]}" "${cmd_check_update[@]}") # force update for SteamCMD or Multi Theft Auto only. diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index b2bd522a8..7c717d0ad 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -660,6 +660,11 @@ fn_update_modules.sh() { fn_fetch_module } +update_etl.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + update_fctr.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index c667a7fe4..8a993b45c 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -80,14 +80,6 @@ fn_install_server_files() { run="norun" force="noforce" md5="2c6be1bb66ea631b9b2e7ae6216c6680" - elif [ "${shortname}" == "etl" ]; then - remote_fileurl="http://linuxgsm.download/WolfensteinEnemyTerritory/etlegacy-v2.78.1-i386-et-260b.tar.xz" - local_filedir="${tmpdir}" - local_filename="etlegacy-v2.78.1-i386-et-260b.tar.xz" - chmodx="nochmodx" - run="norun" - force="noforce" - md5="7c08b52cb09b30eadb98ea05ef780fc7" elif [ "${shortname}" == "mohaa" ]; then remote_fileurl="http://linuxgsm.download/MedalofHonorAlliedAssault/moh_revival_v1.12_RC3.5.1.tar.xz" local_filedir="${tmpdir}" @@ -280,6 +272,8 @@ elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then update_xnt.sh +elif [ "${shortname}" == "etl" ]; then + update_etl.sh elif [ -z "${appid}" ] || [ "${shortname}" == "ahl" ] || [ "${shortname}" == "bb" ] || [ "${shortname}" == "q4" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "sfc" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "vs" ] || [ "${shortname}" == "zmr" ]; then if [ "${shortname}" == "ut" ]; then install_eula.sh diff --git a/lgsm/modules/update_etl.sh b/lgsm/modules/update_etl.sh new file mode 100644 index 000000000..8486343e2 --- /dev/null +++ b/lgsm/modules/update_etl.sh @@ -0,0 +1,173 @@ +#!/bin/bash +# LinuxGSM update_etl.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of ET: Legacy servers. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_dl() { + # Download and extract files to serverfiles. + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "${remotebuildhash}" + fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" + echo "${remotebuild}" > "${serverfiles}/build.txt" + fn_clear_tmp +} + +fn_update_localbuild() { + # Gets local build info. + fn_print_dots "Checking local build: ${remotelocation}" + # Try to get build version from etconsole.log. + if [ -f "${gamelogdir}/etconsole.log" ]; then + localbuild=$(grep "Initializing legacy game" "${gamelogdir}/etconsole.log" | sed -n 's/.*\^2\(v[0-9]\+\.[0-9]\+\.[0-9]\+\).*/\1/p' | tail -1) + fi + # Fall back to build.txt if log parse failed or log does not exist. + if [ -z "${localbuild}" ]; then + localbuild=$(head -n 1 "${serverfiles}/build.txt" 2> /dev/null) + fi + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + fn_script_log_error "Missing local build info" + fn_script_log_error "Set localbuild to 0" + localbuild="0" + else + fn_print_ok "Checking local build: ${remotelocation}" + fn_script_log_pass "Checking local build" + fi +} + +fn_update_remotebuild() { + # Gets remote build info. + apiurl="https://api.github.com/repos/GameServerManagers/etlserver-build/releases/latest" + remotebuildresponse=$(curl -s "${apiurl}") + remotebuildfilename=$(echo "${remotebuildresponse}" | jq -r '.assets[] | select(.browser_download_url | contains("i386-et-260b")) | .name') + remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.assets[] | select(.browser_download_url | contains("i386-et-260b")) | .browser_download_url') + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name') + remotebuildhash=$(echo "${remotebuildresponse}" | jq -r '.body' | grep 'MD5' | grep -oE '[a-f0-9]{32}') + + if [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_dots "Checking remote build: ${remotelocation}" + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then + fn_print_fail "Checking remote build: ${remotelocation}" + fn_script_log_fail "Checking remote build" + core_exit.sh + else + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build" + fi + else + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ]; then + fn_print_failure "Unable to get remote build" + fn_script_log_fail "Unable to get remote build" + core_exit.sh + fi + fi +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then + # Create update lockfile. + date '+%s' > "${lockdir:?}/update.lock" + fn_print_ok_nl "Checking for update: ${remotelocation}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" + fi + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + date +%s > "${lockdir:?}/last-updated.lock" + unset updateonstart + check_status.sh + # If server stopped. + if [ "${status}" == "0" ]; then + fn_update_dl + if [ "${localbuild}" == "0" ]; then + exitbypass=1 + command_start.sh + fn_firstcommand_reset + exitbypass=1 + fn_sleep_time_5 + command_stop.sh + fn_firstcommand_reset + fi + # If server started. + else + fn_print_restart_warning + exitbypass=1 + command_stop.sh + fn_firstcommand_reset + exitbypass=1 + fn_update_dl + exitbypass=1 + command_start.sh + fn_firstcommand_reset + fi + unset exitbypass + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuild: ${remotebuild}" + fi + fi +} + +# The location where the builds are checked and downloaded. +remotelocation="github.com" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi diff --git a/lgsm/modules/update_xnt.sh b/lgsm/modules/update_xnt.sh index 3a937a9f6..501f91c8d 100755 --- a/lgsm/modules/update_xnt.sh +++ b/lgsm/modules/update_xnt.sh @@ -55,6 +55,7 @@ fn_update_remotebuild() { remotebuildfilename="${remotebuildfilename}.zip" remotebuildurl="https://dl.xonotic.org/${remotebuildfilename}" remotebuild="${remotebuildtag}" + remotebuildhash=$(curl -s "https://dl.xonotic.org/${remotebuildfilename%.zip}.sha512" | grep "${remotebuildfilename}$" | grep -oE '[a-f0-9]{128}') if [ "${firstcommandname}" != "INSTALL" ]; then fn_print_dots "Checking remote build: ${remotelocation}" From 9dfbb8eeed4dc49f3979c53ce98d659532606611 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 11:15:31 +0100 Subject: [PATCH 12/53] fix(install_config): replace cp -nv with explicit file existence check (#4897) * fix(install_config): replace cp -nv with explicit file existence check Newer coreutils (Ubuntu 24.04+, Debian 13+) emit a portability warning when using cp -n: 'behavior of -n is non-portable and may change in future'. Replace all cp -nv usages with an explicit [ ! -f dest ] guard, which is portable across all distros and preserves the same OK/SKIP/FAIL behaviour. * fix(install_config): use -e and -L checks to handle broken symlinks Using only -f missed broken symlinks (-e returns false for them but -L returns true). Use both checks to match the skip behaviour of cp -n. --- lgsm/modules/install_config.sh | 33 ++++++++++++++++++++++++++++----- 1 file changed, 28 insertions(+), 5 deletions(-) diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index 41d4ad866..ddfc13794 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -34,8 +34,13 @@ fn_default_config_remote() { if [ "${config}" == "${servercfgdefault}" ]; then mkdir -p "${servercfgdir}" echo -en "copying config file [ ${italic}${servercfgfullpath}${default} ]" - changes+=$(cp -nv "${lgsmdir}/config-default/config-game/${config}" "${servercfgfullpath}") - exitcode=$? + if [ ! -e "${servercfgfullpath}" ] && [ ! -L "${servercfgfullpath}" ]; then + cp "${lgsmdir}/config-default/config-game/${config}" "${servercfgfullpath}" + exitcode=$? + [ "${exitcode}" -eq 0 ] && changes="copied" + else + exitcode=0 + fi if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl fn_script_log_fail "copying config file ${servercfgfullpath}" @@ -48,7 +53,13 @@ fn_default_config_remote() { elif [ "${shortname}" == "arma3" ] && [ "${config}" == "${networkcfgdefault}" ]; then mkdir -p "${servercfgdir}" echo -en "copying config file [ ${italic}${networkcfgfullpath}${default} ]" - changes+=$(cp -nv "${lgsmdir}/config-default/config-game/${config}" "${networkcfgfullpath}") + if [ ! -e "${networkcfgfullpath}" ] && [ ! -L "${networkcfgfullpath}" ]; then + cp "${lgsmdir}/config-default/config-game/${config}" "${networkcfgfullpath}" + exitcode=$? + [ "${exitcode}" -eq 0 ] && changes="copied" + else + exitcode=0 + fi if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl fn_script_log_fail "copying config file ${networkcfgdefault}" @@ -60,7 +71,13 @@ fn_default_config_remote() { fi elif [ "${shortname}" == "dst" ] && [ "${config}" == "${clustercfgdefault}" ]; then echo -en "copying config file [ ${italic}${clustercfgfullpath}${default} ]" - changes+=$(cp -nv "${lgsmdir}/config-default/config-game/${clustercfgdefault}" "${clustercfgfullpath}") + if [ ! -e "${clustercfgfullpath}" ] && [ ! -L "${clustercfgfullpath}" ]; then + cp "${lgsmdir}/config-default/config-game/${clustercfgdefault}" "${clustercfgfullpath}" + exitcode=$? + [ "${exitcode}" -eq 0 ] && changes="copied" + else + exitcode=0 + fi if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl fn_script_log_fail "copying config file ${clustercfgfullpath}" @@ -72,7 +89,13 @@ fn_default_config_remote() { fi else echo -en "copying config file [ ${italic}${servercfgdir}/${config}${default} ]" - changes+=$(cp -nv "${lgsmdir}/config-default/config-game/${config}" "${servercfgdir}/${config}") + if [ ! -e "${servercfgdir}/${config}" ] && [ ! -L "${servercfgdir}/${config}" ]; then + cp "${lgsmdir}/config-default/config-game/${config}" "${servercfgdir}/${config}" + exitcode=$? + [ "${exitcode}" -eq 0 ] && changes="copied" + else + exitcode=0 + fi if [ "${exitcode}" -ne 0 ]; then fn_print_fail_eol_nl fn_script_log_fail "copying config file ${servercfgdir}/${config}" From 0b7aa627c51ea56e39bab8518af4024c50caa009 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:49:03 +0100 Subject: [PATCH 13/53] feat(tf2c): add Team Fortress 2 Classified server (#4898) --- .../config-lgsm/tf2cserver/_default.cfg | 197 ++++++++++++++++++ lgsm/data/serverlist.csv | 1 + lgsm/modules/core_dl.sh | 26 +++ lgsm/modules/install_config.sh | 5 + 4 files changed, 229 insertions(+) create mode 100644 lgsm/config-default/config-lgsm/tf2cserver/_default.cfg diff --git a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg new file mode 100644 index 000000000..baa8c4328 --- /dev/null +++ b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg @@ -0,0 +1,197 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +# Note that for TF2, maxplayers > 33 must be specified like so: +# maxplayers="101 -unrestricted_maxplayers" +ip="0.0.0.0" +port="27015" +clientport="27005" +sourcetvport="27020" +defaultmap="4koth_frigid" +maxplayers="16" + +## Game Server Login Token (GSLT): Optional +# GSLT can be used for running a public server. +# More info: https://docs.linuxgsm.com/steamcmd/gslt +gslt="" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="-game tf2classified -tf_path ${supportdir} -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +baseappid="232250" +appid="3557020" +steamcmdforcewindows="no" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="true" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="3" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="2" +querytype="protocol-valve" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Team Fortress 2 Classified" +engine="source" +glibc="2.15" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/tf2classified" +supportdir="${serverfiles}/tf2" +executabledir="${serverfiles}" +executable="./srcds.sh" +servercfgdir="${systemdir}/cfg" +servercfg="${selfname}.cfg" +servercfgdefault="server.cfg" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 49d7b1d10..2f964a30d 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -114,6 +114,7 @@ sven,svenserver,Sven Co-op,ubuntu-24.04 terraria,terrariaserver,Terraria,ubuntu-24.04 tf,tfserver,The Front,ubuntu-24.04 tf2,tf2server,Team Fortress 2,ubuntu-24.04 +tf2c,tf2cserver,Team Fortress 2 Classified,ubuntu-24.04 tfc,tfcserver,Team Fortress Classic,ubuntu-24.04 ti,tiserver,The Isle,ubuntu-24.04 ts,tsserver,The Specialists,ubuntu-24.04 diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 1c27c58d7..dcbd88e9b 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -81,6 +81,19 @@ fn_dl_steamcmd() { fi # Force Windows Platform type. elif [ "${steamcmdforcewindows}" == "yes" ]; then + # If a base app is required, install it first. + if [ -n "${baseappid}" ]; then + if [ -z "${supportdir}" ]; then + fn_print_failure_nl "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + fn_script_log_fail "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + core_exit.sh + fi + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + if [ "${exitcode}" -ne 0 ]; then + continue + fi + fi if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" elif [ -n "${branch}" ]; then @@ -90,6 +103,19 @@ fn_dl_steamcmd() { fi # All other servers. else + # If a base app is required, install it first. + if [ -n "${baseappid}" ]; then + if [ -z "${supportdir}" ]; then + fn_print_failure_nl "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + fn_script_log_fail "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + core_exit.sh + fi + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + if [ "${exitcode}" -ne 0 ]; then + continue + fi + fi if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" elif [ -n "${branch}" ]; then diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index ddfc13794..4b8148ce9 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -724,6 +724,11 @@ elif [ "${shortname}" == "tf2" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "tf2c" ]; then + array_configs+=(server.cfg) + fn_default_config_remote + fn_set_config_vars + fn_list_config_locations elif [ "${shortname}" == "tfc" ]; then array_configs+=(server.cfg) fn_default_config_remote From 7e472ba9accefa06267211b23b7e1fa13a38c02a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 19:54:24 +0000 Subject: [PATCH 14/53] Release v26.1.0 --- lgsm/modules/core_modules.sh | 2 +- linuxgsm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 7c717d0ad..10d408449 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -8,7 +8,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -modulesversion="v25.2.0" +modulesversion="v26.1.0" # Core diff --git a/linuxgsm.sh b/linuxgsm.sh index 443e1d8bf..f664749e6 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -24,7 +24,7 @@ if [ -f ".dev-debug" ]; then set -x fi -version="v25.2.0" +version="v26.1.0" shortname="core" gameservername="core" commandname="CORE" From a7186b8f7f44b3448b18ce5d3adf54c29f9258fe Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:12:16 +0000 Subject: [PATCH 15/53] fix(alert_slack): add missing closing brace on section object The 'section' block containing 'fields' and 'accessory' was missing its closing '}' before EOF, producing malformed JSON and breaking all Slack alerts silently (jq -c . would fail on the payload). Also add missing ntfy alert settings to tf2cserver _default.cfg for consistency with other server configs. --- .../config-default/config-lgsm/tf2cserver/_default.cfg | 10 ++++++++++ lgsm/modules/alert_slack.sh | 1 + 2 files changed, 11 insertions(+) diff --git a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg index baa8c4328..fdbcc2cba 100644 --- a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg @@ -65,6 +65,16 @@ iftttalert="off" ifttttoken="accesstoken" iftttevent="linuxgsm_alert" +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + # Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet pushbulletalert="off" pushbullettoken="accesstoken" diff --git a/lgsm/modules/alert_slack.sh b/lgsm/modules/alert_slack.sh index defb1f77f..0cd7106ff 100755 --- a/lgsm/modules/alert_slack.sh +++ b/lgsm/modules/alert_slack.sh @@ -60,6 +60,7 @@ json=$( "image_url": "${alerticon}", "alt_text": "LinuxGSM game icon" } + } EOF ) From d04d5b6dfdcc34d844fc92b5bc1ab9c3b4f1de46 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:16:40 +0000 Subject: [PATCH 16/53] fix: address review feedback - core_dl.sh: use array assignment for steamcmdcommand instead of read -r -a to avoid word-splitting on paths - fix_st.sh: correct module header typo (fix_ts.sh -> fix_st.sh) - command_skeleton.sh: fix grammar 'Creates an copy' -> 'Creates a copy' - serverlist-validate-game-icons.sh: anchor grep to start-of-line and require trailing comma to prevent false positives (e.g. 'tf' matching 'tf2' entries) - cs2server/_default.cfg: remove duplicate ntfy alert settings block --- .github/workflows/serverlist-validate-game-icons.sh | 2 +- lgsm/config-default/config-lgsm/cs2server/_default.cfg | 10 ---------- lgsm/modules/command_skeleton.sh | 2 +- lgsm/modules/core_dl.sh | 6 +++--- lgsm/modules/fix_st.sh | 2 +- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/.github/workflows/serverlist-validate-game-icons.sh b/.github/workflows/serverlist-validate-game-icons.sh index b3ba7e418..8d35aa906 100755 --- a/.github/workflows/serverlist-validate-game-icons.sh +++ b/.github/workflows/serverlist-validate-game-icons.sh @@ -22,7 +22,7 @@ shopt -s nullglob for gameiconpath in gameicons/*; do gameicon="$(basename "${gameiconpath}")" # check if $gameicon is in serverlist.csv - if ! grep -q -F "${gameicon%-icon.png}" serverlist.csv; then + if ! grep -q -E "^${gameicon%-icon.png}," serverlist.csv; then echo "ERROR: gameicon ${gameicon} is not in serverlist.csv" exitcode=1 else diff --git a/lgsm/config-default/config-lgsm/cs2server/_default.cfg b/lgsm/config-default/config-lgsm/cs2server/_default.cfg index 56948c77f..8d65b5364 100644 --- a/lgsm/config-default/config-lgsm/cs2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cs2server/_default.cfg @@ -72,16 +72,6 @@ ntfypassword="" ntfypriority="" ntfytags="" -# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy -ntfyalert="off" -ntfytopic="LinuxGSM" -ntfyserver="https://ntfy.sh" -ntfytoken="" -ntfyusername="" -ntfypassword="" -ntfypriority="" -ntfytags="" - # Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet pushbulletalert="off" pushbullettoken="accesstoken" diff --git a/lgsm/modules/command_skeleton.sh b/lgsm/modules/command_skeleton.sh index 687790a37..3e07edc3a 100755 --- a/lgsm/modules/command_skeleton.sh +++ b/lgsm/modules/command_skeleton.sh @@ -3,7 +3,7 @@ # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com -# Description: Creates an copy of a game servers directories. +# Description: Creates a copy of a game server directories. commandname="SKELETON" commandaction="Skeleton" diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index dcbd88e9b..4730c0cff 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -46,9 +46,9 @@ fn_dl_steamcmd() { validate="validate" fi - # steamcmdcommand can contain multiple arguments; treat it as an argv array. - steamcmdcommandarray=() - read -r -a steamcmdcommandarray <<< "${steamcmdcommand}" + # Wrap steamcmdcommand as a single-element array to avoid word-splitting + # on paths/commands that should not be tokenised. + steamcmdcommandarray=("${steamcmdcommand}") unbuffercommand=() if [ -n "${unbuffer}" ]; then unbuffercommand=("${unbuffer}") diff --git a/lgsm/modules/fix_st.sh b/lgsm/modules/fix_st.sh index 598d971b0..887ea987f 100755 --- a/lgsm/modules/fix_st.sh +++ b/lgsm/modules/fix_st.sh @@ -1,5 +1,5 @@ #!/bin/bash -# LinuxGSM fix_ts.sh module +# LinuxGSM fix_st.sh module # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com From 329660d8b97b75c18ba579b925161ae5978ebb80 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:51:10 +0000 Subject: [PATCH 17/53] fix(vints): assign remotebuild instead of unused remotebuildversion The API version lookup was setting remotebuildversion but all subsequent jq queries used ${remotebuild}, which was never populated. This caused 'Unable to get remote build' on every install/update. --- lgsm/modules/update_vints.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/update_vints.sh b/lgsm/modules/update_vints.sh index 86a7156ee..5bf3df25d 100755 --- a/lgsm/modules/update_vints.sh +++ b/lgsm/modules/update_vints.sh @@ -39,11 +39,11 @@ fn_update_remotebuild() { apiurl="http://api.vintagestory.at/stable-unstable.json" remotebuildresponse=$(curl -s "${apiurl}") if [ "${branch}" == "stable" ]; then - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -Ev "\-rc|\-pre" | sort -r -V | head -1) + remotebuild=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -Ev "\-rc|\-pre" | sort -r -V | head -1) elif [ "${branch}" == "unstable" ]; then - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -E "\-rc|\-pre" | sort -r -V | head -1) + remotebuild=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -E "\-rc|\-pre" | sort -r -V | head -1) else - remotebuildversion="${branch}" + remotebuild="${branch}" fi remotebuildfilename=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.filename') remotebuildurl=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.urls.cdn') From a14433c2f0f62c593bccab58e4668eb114eb0423 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 21:01:35 +0000 Subject: [PATCH 18/53] fix(xnt): unset exitbypass after command_stop.sh in fn_update_localbuild --- lgsm/modules/update_xnt.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lgsm/modules/update_xnt.sh b/lgsm/modules/update_xnt.sh index 501f91c8d..904b7b1a4 100755 --- a/lgsm/modules/update_xnt.sh +++ b/lgsm/modules/update_xnt.sh @@ -29,7 +29,9 @@ fn_update_localbuild() { exitbypass=1 fn_sleep_time_5 tmux -L "${socketname}" send-keys -t "${sessionname}" "version" C-m > /dev/null 2>&1 + exitbypass=1 command_stop.sh + unset exitbypass fn_firstcommand_reset fi From db4253f002209b9cb1b489ea38a2de93f4553071 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 21:06:52 +0000 Subject: [PATCH 19/53] fix(ci): resolve super-linter failures - Set DEFAULT_BRANCH to current branch to fix 'master not found' error - Use fetch-depth: 0 so GITHUB_BEFORE_SHA can be resolved - Set update_etl.sh executable bit (BASH_EXEC) - Fix .codespellrc tab indentation (EDITORCONFIG) - Add .gitleaks.toml allowlist for GA4 Measurement Protocol API secret (GITLEAKS) - Fix .markdown-lint.yml: disable MD030/MD013/MD033/MD041/MD051 to match existing repo style (MARKDOWN) --- .github/linters/.codespellrc | 10 +++++----- .github/linters/.gitleaks.toml | 9 +++++++++ .github/linters/.markdown-lint.yml | 11 ++++------- .github/workflows/action-super-linter.yml | 6 +++--- lgsm/modules/update_etl.sh | 0 5 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 .github/linters/.gitleaks.toml mode change 100644 => 100755 lgsm/modules/update_etl.sh diff --git a/.github/linters/.codespellrc b/.github/linters/.codespellrc index 229066881..47dd5ccea 100644 --- a/.github/linters/.codespellrc +++ b/.github/linters/.codespellrc @@ -1,11 +1,11 @@ [codespell] # Skip data tables that contain many short server identifiers (e.g. "fof", "nd") skip = - lgsm/data/*.csv, - package-lock.json, - */package-lock.json, - node_modules, - */node_modules/* + lgsm/data/*.csv, + package-lock.json, + */package-lock.json, + node_modules, + */node_modules/* # Ignore common identifiers/acronyms and extensions used throughout LinuxGSM ignore-words-list = distroname,fof,nd,sav,parms,ThirdParty diff --git a/.github/linters/.gitleaks.toml b/.github/linters/.gitleaks.toml new file mode 100644 index 000000000..b61845ba6 --- /dev/null +++ b/.github/linters/.gitleaks.toml @@ -0,0 +1,9 @@ +title = "LinuxGSM Gitleaks Config" + +[allowlist] + description = "Known false positives" + regexes = [ + # Google Analytics 4 Measurement Protocol API secret - not a sensitive credential, + # it is intentionally embedded in client-side code and is safe to be public. + '''apisecret="[A-Za-z0-9_\-]+"''', + ] diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml index 094bbbcd6..62d421814 100644 --- a/.github/linters/.markdown-lint.yml +++ b/.github/linters/.markdown-lint.yml @@ -12,12 +12,9 @@ MD013: false # MD033: The main README uses inline HTML for badges. MD033: false -# Match existing list formatting in this repo. +# MD007: Repo uses 2-space indentation for nested lists. MD007: - indent: 4 + indent: 2 -MD030: - ul_single: 3 - ol_single: 2 - ul_multi: 3 - ol_multi: 2 +# MD030: Repo mixes 1-space unordered and 2-space ordered list markers. +MD030: false diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index de396dcd4..e2755e20a 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -27,9 +27,8 @@ jobs: - name: Checkout code uses: actions/checkout@v6 with: - # Shallow clone reduces transient fetch failures (HTTP 500) from GitHub. - # We lint the whole codebase instead of relying on git history. - fetch-depth: 1 + # Full clone required so super-linter can resolve GITHUB_BEFORE_SHA. + fetch-depth: 0 fetch-tags: false persist-credentials: false @@ -42,6 +41,7 @@ jobs: env: # To report GitHub Actions status checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEFAULT_BRANCH: ${{ github.ref_name }} VALIDATE_BIOME_FORMAT: false VALIDATE_BIOME_LINT: false VALIDATE_GITHUB_ACTIONS_ZIZMOR: false diff --git a/lgsm/modules/update_etl.sh b/lgsm/modules/update_etl.sh old mode 100644 new mode 100755 From a974fa2f70d01b2deca022c7c32e7122ad9ff0f7 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:49:03 +0100 Subject: [PATCH 20/53] feat(tf2c): add Team Fortress 2 Classified server (#4898) --- .../config-lgsm/tf2cserver/_default.cfg | 197 ++++++++++++++++++ lgsm/data/serverlist.csv | 1 + lgsm/modules/core_dl.sh | 26 +++ lgsm/modules/install_config.sh | 5 + 4 files changed, 229 insertions(+) create mode 100644 lgsm/config-default/config-lgsm/tf2cserver/_default.cfg diff --git a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg new file mode 100644 index 000000000..baa8c4328 --- /dev/null +++ b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg @@ -0,0 +1,197 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +# Note that for TF2, maxplayers > 33 must be specified like so: +# maxplayers="101 -unrestricted_maxplayers" +ip="0.0.0.0" +port="27015" +clientport="27005" +sourcetvport="27020" +defaultmap="4koth_frigid" +maxplayers="16" + +## Game Server Login Token (GSLT): Optional +# GSLT can be used for running a public server. +# More info: https://docs.linuxgsm.com/steamcmd/gslt +gslt="" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="-game tf2classified -tf_path ${supportdir} -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +sv_setsteamaccount ${gslt} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +baseappid="232250" +appid="3557020" +steamcmdforcewindows="no" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="true" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="3" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="2" +querytype="protocol-valve" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Team Fortress 2 Classified" +engine="source" +glibc="2.15" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/tf2classified" +supportdir="${serverfiles}/tf2" +executabledir="${serverfiles}" +executable="./srcds.sh" +servercfgdir="${systemdir}/cfg" +servercfg="${selfname}.cfg" +servercfgdefault="server.cfg" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 49d7b1d10..2f964a30d 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -114,6 +114,7 @@ sven,svenserver,Sven Co-op,ubuntu-24.04 terraria,terrariaserver,Terraria,ubuntu-24.04 tf,tfserver,The Front,ubuntu-24.04 tf2,tf2server,Team Fortress 2,ubuntu-24.04 +tf2c,tf2cserver,Team Fortress 2 Classified,ubuntu-24.04 tfc,tfcserver,Team Fortress Classic,ubuntu-24.04 ti,tiserver,The Isle,ubuntu-24.04 ts,tsserver,The Specialists,ubuntu-24.04 diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 1c27c58d7..dcbd88e9b 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -81,6 +81,19 @@ fn_dl_steamcmd() { fi # Force Windows Platform type. elif [ "${steamcmdforcewindows}" == "yes" ]; then + # If a base app is required, install it first. + if [ -n "${baseappid}" ]; then + if [ -z "${supportdir}" ]; then + fn_print_failure_nl "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + fn_script_log_fail "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + core_exit.sh + fi + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + if [ "${exitcode}" -ne 0 ]; then + continue + fi + fi if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +@sSteamCmdForcePlatformType windows +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" elif [ -n "${branch}" ]; then @@ -90,6 +103,19 @@ fn_dl_steamcmd() { fi # All other servers. else + # If a base app is required, install it first. + if [ -n "${baseappid}" ]; then + if [ -z "${supportdir}" ]; then + fn_print_failure_nl "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + fn_script_log_fail "${commandaction} ${selfname}: baseappid is set but supportdir is not defined" + core_exit.sh + fi + "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${supportdir}" +login "${steamuser}" "${steampass}" +app_update "${baseappid}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" + exitcode="${PIPESTATUS[0]}" + if [ "${exitcode}" -ne 0 ]; then + continue + fi + fi if [ -n "${branch}" ] && [ -n "${betapassword}" ]; then "${unbuffercommand[@]}" "${steamcmdcommandarray[@]}" +force_install_dir "${serverfiles}" +login "${steamuser}" "${steampass}" +app_update "${appid}" -beta "${branch}" -betapassword "${betapassword}" "${validateparam[@]}" +quit | uniq | tee -a "${lgsmlog}" "${steamcmdlog}" elif [ -n "${branch}" ]; then diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index ddfc13794..4b8148ce9 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -724,6 +724,11 @@ elif [ "${shortname}" == "tf2" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "tf2c" ]; then + array_configs+=(server.cfg) + fn_default_config_remote + fn_set_config_vars + fn_list_config_locations elif [ "${shortname}" == "tfc" ]; then array_configs+=(server.cfg) fn_default_config_remote From 96acbd779a7cf2193bfb9261c4a7e7104edbebc5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 19:54:24 +0000 Subject: [PATCH 21/53] Release v26.1.0 --- lgsm/modules/core_modules.sh | 2 +- linuxgsm.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 7c717d0ad..10d408449 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -8,7 +8,7 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" -modulesversion="v25.2.0" +modulesversion="v26.1.0" # Core diff --git a/linuxgsm.sh b/linuxgsm.sh index 443e1d8bf..f664749e6 100755 --- a/linuxgsm.sh +++ b/linuxgsm.sh @@ -24,7 +24,7 @@ if [ -f ".dev-debug" ]; then set -x fi -version="v25.2.0" +version="v26.1.0" shortname="core" gameservername="core" commandname="CORE" From ec63aae5ef59fd6f134fa95ecf53c5a046f1dba6 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:12:16 +0000 Subject: [PATCH 22/53] fix(alert_slack): add missing closing brace on section object The 'section' block containing 'fields' and 'accessory' was missing its closing '}' before EOF, producing malformed JSON and breaking all Slack alerts silently (jq -c . would fail on the payload). Also add missing ntfy alert settings to tf2cserver _default.cfg for consistency with other server configs. --- .../config-default/config-lgsm/tf2cserver/_default.cfg | 10 ++++++++++ lgsm/modules/alert_slack.sh | 1 + 2 files changed, 11 insertions(+) diff --git a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg index baa8c4328..fdbcc2cba 100644 --- a/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg +++ b/lgsm/config-default/config-lgsm/tf2cserver/_default.cfg @@ -65,6 +65,16 @@ iftttalert="off" ifttttoken="accesstoken" iftttevent="linuxgsm_alert" +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + # Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet pushbulletalert="off" pushbullettoken="accesstoken" diff --git a/lgsm/modules/alert_slack.sh b/lgsm/modules/alert_slack.sh index defb1f77f..0cd7106ff 100755 --- a/lgsm/modules/alert_slack.sh +++ b/lgsm/modules/alert_slack.sh @@ -60,6 +60,7 @@ json=$( "image_url": "${alerticon}", "alt_text": "LinuxGSM game icon" } + } EOF ) From 6e4480c6567308e858befa4b0c83cc5a14d0829d Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:16:40 +0000 Subject: [PATCH 23/53] fix: address review feedback - core_dl.sh: use array assignment for steamcmdcommand instead of read -r -a to avoid word-splitting on paths - fix_st.sh: correct module header typo (fix_ts.sh -> fix_st.sh) - command_skeleton.sh: fix grammar 'Creates an copy' -> 'Creates a copy' - serverlist-validate-game-icons.sh: anchor grep to start-of-line and require trailing comma to prevent false positives (e.g. 'tf' matching 'tf2' entries) - cs2server/_default.cfg: remove duplicate ntfy alert settings block --- .github/workflows/serverlist-validate-game-icons.sh | 2 +- lgsm/config-default/config-lgsm/cs2server/_default.cfg | 10 ---------- lgsm/modules/command_skeleton.sh | 2 +- lgsm/modules/core_dl.sh | 6 +++--- lgsm/modules/fix_st.sh | 2 +- 5 files changed, 6 insertions(+), 16 deletions(-) diff --git a/.github/workflows/serverlist-validate-game-icons.sh b/.github/workflows/serverlist-validate-game-icons.sh index b3ba7e418..8d35aa906 100755 --- a/.github/workflows/serverlist-validate-game-icons.sh +++ b/.github/workflows/serverlist-validate-game-icons.sh @@ -22,7 +22,7 @@ shopt -s nullglob for gameiconpath in gameicons/*; do gameicon="$(basename "${gameiconpath}")" # check if $gameicon is in serverlist.csv - if ! grep -q -F "${gameicon%-icon.png}" serverlist.csv; then + if ! grep -q -E "^${gameicon%-icon.png}," serverlist.csv; then echo "ERROR: gameicon ${gameicon} is not in serverlist.csv" exitcode=1 else diff --git a/lgsm/config-default/config-lgsm/cs2server/_default.cfg b/lgsm/config-default/config-lgsm/cs2server/_default.cfg index 56948c77f..8d65b5364 100644 --- a/lgsm/config-default/config-lgsm/cs2server/_default.cfg +++ b/lgsm/config-default/config-lgsm/cs2server/_default.cfg @@ -72,16 +72,6 @@ ntfypassword="" ntfypriority="" ntfytags="" -# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy -ntfyalert="off" -ntfytopic="LinuxGSM" -ntfyserver="https://ntfy.sh" -ntfytoken="" -ntfyusername="" -ntfypassword="" -ntfypriority="" -ntfytags="" - # Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet pushbulletalert="off" pushbullettoken="accesstoken" diff --git a/lgsm/modules/command_skeleton.sh b/lgsm/modules/command_skeleton.sh index 687790a37..3e07edc3a 100755 --- a/lgsm/modules/command_skeleton.sh +++ b/lgsm/modules/command_skeleton.sh @@ -3,7 +3,7 @@ # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com -# Description: Creates an copy of a game servers directories. +# Description: Creates a copy of a game server directories. commandname="SKELETON" commandaction="Skeleton" diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index dcbd88e9b..4730c0cff 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -46,9 +46,9 @@ fn_dl_steamcmd() { validate="validate" fi - # steamcmdcommand can contain multiple arguments; treat it as an argv array. - steamcmdcommandarray=() - read -r -a steamcmdcommandarray <<< "${steamcmdcommand}" + # Wrap steamcmdcommand as a single-element array to avoid word-splitting + # on paths/commands that should not be tokenised. + steamcmdcommandarray=("${steamcmdcommand}") unbuffercommand=() if [ -n "${unbuffer}" ]; then unbuffercommand=("${unbuffer}") diff --git a/lgsm/modules/fix_st.sh b/lgsm/modules/fix_st.sh index 598d971b0..887ea987f 100755 --- a/lgsm/modules/fix_st.sh +++ b/lgsm/modules/fix_st.sh @@ -1,5 +1,5 @@ #!/bin/bash -# LinuxGSM fix_ts.sh module +# LinuxGSM fix_st.sh module # Author: Daniel Gibbs # Contributors: https://linuxgsm.com/contrib # Website: https://linuxgsm.com From c864cb596b5e678879ca5f5ae4100d92d9f72e91 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 20:51:10 +0000 Subject: [PATCH 24/53] fix(vints): assign remotebuild instead of unused remotebuildversion The API version lookup was setting remotebuildversion but all subsequent jq queries used ${remotebuild}, which was never populated. This caused 'Unable to get remote build' on every install/update. --- lgsm/modules/update_vints.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lgsm/modules/update_vints.sh b/lgsm/modules/update_vints.sh index 86a7156ee..5bf3df25d 100755 --- a/lgsm/modules/update_vints.sh +++ b/lgsm/modules/update_vints.sh @@ -39,11 +39,11 @@ fn_update_remotebuild() { apiurl="http://api.vintagestory.at/stable-unstable.json" remotebuildresponse=$(curl -s "${apiurl}") if [ "${branch}" == "stable" ]; then - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -Ev "\-rc|\-pre" | sort -r -V | head -1) + remotebuild=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -Ev "\-rc|\-pre" | sort -r -V | head -1) elif [ "${branch}" == "unstable" ]; then - remotebuildversion=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -E "\-rc|\-pre" | sort -r -V | head -1) + remotebuild=$(echo "${remotebuildresponse}" | jq -r '[ to_entries[] ] | .[].key' | grep -E "\-rc|\-pre" | sort -r -V | head -1) else - remotebuildversion="${branch}" + remotebuild="${branch}" fi remotebuildfilename=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.filename') remotebuildurl=$(echo "${remotebuildresponse}" | jq --arg remotebuild "${remotebuild}" -r '.[$remotebuild].linuxserver.urls.cdn') From 1fdd43a6adeb1839da62660d8c54cdf4fd37f008 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 21:01:35 +0000 Subject: [PATCH 25/53] fix(xnt): unset exitbypass after command_stop.sh in fn_update_localbuild --- lgsm/modules/update_xnt.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lgsm/modules/update_xnt.sh b/lgsm/modules/update_xnt.sh index 501f91c8d..904b7b1a4 100755 --- a/lgsm/modules/update_xnt.sh +++ b/lgsm/modules/update_xnt.sh @@ -29,7 +29,9 @@ fn_update_localbuild() { exitbypass=1 fn_sleep_time_5 tmux -L "${socketname}" send-keys -t "${sessionname}" "version" C-m > /dev/null 2>&1 + exitbypass=1 command_stop.sh + unset exitbypass fn_firstcommand_reset fi From fdb86257e0ee7bc476ebf2f4c29cef058199165e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 21:06:52 +0000 Subject: [PATCH 26/53] fix(ci): resolve super-linter failures - Set DEFAULT_BRANCH to current branch to fix 'master not found' error - Use fetch-depth: 0 so GITHUB_BEFORE_SHA can be resolved - Set update_etl.sh executable bit (BASH_EXEC) - Fix .codespellrc tab indentation (EDITORCONFIG) - Add .gitleaks.toml allowlist for GA4 Measurement Protocol API secret (GITLEAKS) - Fix .markdown-lint.yml: disable MD030/MD013/MD033/MD041/MD051 to match existing repo style (MARKDOWN) --- .github/linters/.codespellrc | 10 +++++----- .github/linters/.gitleaks.toml | 9 +++++++++ .github/linters/.markdown-lint.yml | 11 ++++------- .github/workflows/action-super-linter.yml | 6 +++--- lgsm/modules/update_etl.sh | 0 5 files changed, 21 insertions(+), 15 deletions(-) create mode 100644 .github/linters/.gitleaks.toml mode change 100644 => 100755 lgsm/modules/update_etl.sh diff --git a/.github/linters/.codespellrc b/.github/linters/.codespellrc index 229066881..47dd5ccea 100644 --- a/.github/linters/.codespellrc +++ b/.github/linters/.codespellrc @@ -1,11 +1,11 @@ [codespell] # Skip data tables that contain many short server identifiers (e.g. "fof", "nd") skip = - lgsm/data/*.csv, - package-lock.json, - */package-lock.json, - node_modules, - */node_modules/* + lgsm/data/*.csv, + package-lock.json, + */package-lock.json, + node_modules, + */node_modules/* # Ignore common identifiers/acronyms and extensions used throughout LinuxGSM ignore-words-list = distroname,fof,nd,sav,parms,ThirdParty diff --git a/.github/linters/.gitleaks.toml b/.github/linters/.gitleaks.toml new file mode 100644 index 000000000..b61845ba6 --- /dev/null +++ b/.github/linters/.gitleaks.toml @@ -0,0 +1,9 @@ +title = "LinuxGSM Gitleaks Config" + +[allowlist] + description = "Known false positives" + regexes = [ + # Google Analytics 4 Measurement Protocol API secret - not a sensitive credential, + # it is intentionally embedded in client-side code and is safe to be public. + '''apisecret="[A-Za-z0-9_\-]+"''', + ] diff --git a/.github/linters/.markdown-lint.yml b/.github/linters/.markdown-lint.yml index 094bbbcd6..62d421814 100644 --- a/.github/linters/.markdown-lint.yml +++ b/.github/linters/.markdown-lint.yml @@ -12,12 +12,9 @@ MD013: false # MD033: The main README uses inline HTML for badges. MD033: false -# Match existing list formatting in this repo. +# MD007: Repo uses 2-space indentation for nested lists. MD007: - indent: 4 + indent: 2 -MD030: - ul_single: 3 - ol_single: 2 - ul_multi: 3 - ol_multi: 2 +# MD030: Repo mixes 1-space unordered and 2-space ordered list markers. +MD030: false diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index de396dcd4..e2755e20a 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -27,9 +27,8 @@ jobs: - name: Checkout code uses: actions/checkout@v6 with: - # Shallow clone reduces transient fetch failures (HTTP 500) from GitHub. - # We lint the whole codebase instead of relying on git history. - fetch-depth: 1 + # Full clone required so super-linter can resolve GITHUB_BEFORE_SHA. + fetch-depth: 0 fetch-tags: false persist-credentials: false @@ -42,6 +41,7 @@ jobs: env: # To report GitHub Actions status checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DEFAULT_BRANCH: ${{ github.ref_name }} VALIDATE_BIOME_FORMAT: false VALIDATE_BIOME_LINT: false VALIDATE_GITHUB_ACTIONS_ZIZMOR: false diff --git a/lgsm/modules/update_etl.sh b/lgsm/modules/update_etl.sh old mode 100644 new mode 100755 From 9a61c0f4c6db6a9d0d8943bd8f8ab32988377cd5 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 19 Apr 2026 21:44:26 +0000 Subject: [PATCH 27/53] chore(ci): upgrade webfactory/ssh-agent from v0.9.0 to v0.10.0 v0.10.0 upgrades from Node.js 20 to Node.js 24, resolving the deprecation warning ahead of the June 2026 forced migration. --- .github/workflows/git-sync.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/git-sync.yml b/.github/workflows/git-sync.yml index 42c660d9b..986346c49 100644 --- a/.github/workflows/git-sync.yml +++ b/.github/workflows/git-sync.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: SSH Agent - uses: webfactory/ssh-agent@v0.9.0 + uses: webfactory/ssh-agent@v0.10.0 with: ssh-private-key: ${{ secrets.BITBUCKET_SECRET }} From 445dddbd212833ad80808f9f0c0a8b78b010645e Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 24 Apr 2026 18:49:19 +0100 Subject: [PATCH 28/53] fix(steamcmd): add libtinfo.so.5 symlink fix for readline warning (#4899) * fix(steamcmd): add libtinfo.so.5 symlink fix for readline warning On distros shipping libtinfo.so.6 but not libtinfo.so.5 (Ubuntu 22.04+, Debian 12+), SteamCMD prints: WARNING: Failed to load 32-bit libtinfo.so.5 or libncurses.so.5. Please install (lib32tinfo5 / ncurses-libs.i686 / equivalent) to enable readline. lib32tinfo5 does not exist on Ubuntu 24.04. Creating a user-space symlink inside the steamcmd directory resolves the warning without requiring root or a missing package. * fix(steamcmd): address Copilot review feedback on libtinfo symlink fix - Iterate over all candidate steamcmd dirs (HOME/.steam/steamcmd, steamcmddir, HOME/.local/share/Steam/steamcmd) matching the pattern used for steamclient.so fixes elsewhere in the module - Replace '! -f && ! -L' guard with '! -e' so broken/dangling symlinks are also repaired rather than silently skipped - Add mkdir -p before ln in case the directory does not exist yet - Capture exitcode=$? after ln so fn_fix_msg_end reports failures --------- Co-authored-by: LinuxGSM --- lgsm/modules/fix_steamcmd.sh | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/lgsm/modules/fix_steamcmd.sh b/lgsm/modules/fix_steamcmd.sh index 0ba5c85b2..36bc378ac 100755 --- a/lgsm/modules/fix_steamcmd.sh +++ b/lgsm/modules/fix_steamcmd.sh @@ -113,6 +113,31 @@ if [ ! -f "${steamclientsdk32}" ]; then fn_fix_msg_end fi +# Helps fix: WARNING: Failed to load 32-bit libtinfo.so.5 or libncurses.so.5. +# On distros that ship libtinfo.so.6 (e.g. Ubuntu 22.04+, Debian 12+) but not +# libtinfo.so.5, SteamCMD prints this warning and loses readline support. +# Creating a symlink from .so.5 -> .so.6 resolves the warning without root. +for libtinfo32dir in "${HOME}/.steam/steamcmd" "${steamcmddir}" "${HOME}/.local/share/Steam/steamcmd"; do + if [ -d "${libtinfo32dir}" ]; then + libtinfo32so="${libtinfo32dir}/libtinfo.so.5" + # Also repair broken symlinks (! -e catches missing target, -L catches dangling link) + if [ ! -e "${libtinfo32so}" ]; then + # Find the .so.6 in the system 32-bit lib paths + for libtinfo32so6 in /lib/i386-linux-gnu/libtinfo.so.6 /usr/lib/i386-linux-gnu/libtinfo.so.6 /lib32/libtinfo.so.6; do + if [ -f "${libtinfo32so6}" ]; then + fixname="libtinfo.so.5 32-bit symlink" + fn_fix_msg_start + mkdir -p "${libtinfo32dir}" + ln -sf "${libtinfo32so6}" "${libtinfo32so}" + exitcode=$? + fn_fix_msg_end + break + fi + done + fi + fi +done + # steamclient.so fixes if [ "${shortname}" == "bo" ]; then fn_fix_steamclient_so "32" "${serverfiles}/BODS_Data/Plugins/x86" From 5a3c210ab78b9fc2a704511b0639c8db0518f038 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Fri, 24 Apr 2026 20:56:48 +0100 Subject: [PATCH 29/53] feat(newserver): Military Conflict: Vietnam MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add support for the Military Conflict: Vietnam dedicated game server. Supersedes #4594 (original WIP PR from @knoxed โ€” completing the implementation). Changes: - Added mcvserver default configuration - Added mcv to serverlist and all distro CSV files - Added install_config handler for mcvserver - Added dependency info for all distros - Added game icons - Fixed CI workflow issues Co-authored-by: Knoxed <1338733+knoxed@users.noreply.github.com> --- .github/workflows/details-check.yml | 2 +- .github/workflows/serverlist-validate.yml | 5 +- ...update-copyright-years-in-license-file.yml | 2 +- .github/workflows/version-check.yml | 2 +- .../config-lgsm/mcvserver/_default.cfg | 189 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 4 +- lgsm/data/almalinux-9.csv | 4 +- lgsm/data/centos-7.csv | 4 +- lgsm/data/centos-8.csv | 4 +- lgsm/data/centos-9.csv | 4 +- lgsm/data/debian-10.csv | 2 + lgsm/data/debian-11.csv | 2 + lgsm/data/debian-12.csv | 2 + lgsm/data/debian-13.csv | 2 + lgsm/data/debian-9.csv | 2 + lgsm/data/gameicons/mcv-icon.png | Bin 0 -> 2334 bytes lgsm/data/gameicons/ps-icon.png | Bin 1216 -> 0 bytes lgsm/data/gameicons/squad44-icon.png | Bin 0 -> 1849 bytes lgsm/data/gameicons/tf2c-icon.png | Bin 0 -> 2412 bytes lgsm/data/rhel-7.csv | 4 +- lgsm/data/rhel-8.csv | 4 +- lgsm/data/rhel-9.csv | 4 +- lgsm/data/rocky-8.csv | 4 +- lgsm/data/rocky-9.csv | 4 +- lgsm/data/serverlist.csv | 1 + lgsm/data/ubuntu-16.04.csv | 2 + lgsm/data/ubuntu-18.04.csv | 2 + lgsm/data/ubuntu-20.04.csv | 2 + lgsm/data/ubuntu-22.04.csv | 2 + lgsm/data/ubuntu-23.04.csv | 2 + lgsm/data/ubuntu-23.10.csv | 2 + lgsm/data/ubuntu-24.04.csv | 4 +- lgsm/modules/install_config.sh | 5 + 33 files changed, 257 insertions(+), 15 deletions(-) create mode 100644 lgsm/config-default/config-lgsm/mcvserver/_default.cfg create mode 100644 lgsm/data/gameicons/mcv-icon.png delete mode 100644 lgsm/data/gameicons/ps-icon.png create mode 100644 lgsm/data/gameicons/squad44-icon.png create mode 100644 lgsm/data/gameicons/tf2c-icon.png diff --git a/.github/workflows/details-check.yml b/.github/workflows/details-check.yml index c58aa0ae4..aced7522d 100644 --- a/.github/workflows/details-check.yml +++ b/.github/workflows/details-check.yml @@ -21,7 +21,7 @@ jobs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Generate matrix with generate-matrix.sh run: chmod +x .github/workflows/details-check-generate-matrix.sh; .github/workflows/details-check-generate-matrix.sh diff --git a/.github/workflows/serverlist-validate.yml b/.github/workflows/serverlist-validate.yml index c2605b062..e2016eddf 100644 --- a/.github/workflows/serverlist-validate.yml +++ b/.github/workflows/serverlist-validate.yml @@ -6,13 +6,16 @@ on: permissions: contents: read +env: + datadir: lgsm/data + jobs: serverlist-validate: if: github.repository_owner == 'GameServerManagers' runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Compare Versions run: chmod +x .github/workflows/serverlist-validate.sh; .github/workflows/serverlist-validate.sh diff --git a/.github/workflows/update-copyright-years-in-license-file.yml b/.github/workflows/update-copyright-years-in-license-file.yml index 1123b8cce..d9870a166 100644 --- a/.github/workflows/update-copyright-years-in-license-file.yml +++ b/.github/workflows/update-copyright-years-in-license-file.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 with: fetch-depth: 0 - name: Action Update License Year diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index cfa7615bd..2b4448643 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Version Check run: chmod +x .github/workflows/version-check.sh; .github/workflows/version-check.sh diff --git a/lgsm/config-default/config-lgsm/mcvserver/_default.cfg b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg new file mode 100644 index 000000000..3d822892a --- /dev/null +++ b/lgsm/config-default/config-lgsm/mcvserver/_default.cfg @@ -0,0 +1,189 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +game_type="0" +game_mode="0" +ip="0.0.0.0" +port="27015" +clientport="27005" +sourcetvport="27020" +steamport="26901" +defaultmap="mcv_siege" +maxplayers="32" +tickrate="64" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="-game vietnam -usercon -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} -tickrate ${tickrate} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers_override ${maxplayers} +game_type ${game_type} +game_mode ${game_mode} -nobreakpad" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +curlcustomstring="" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +appid="1136190" +steamcmdforcewindows="no" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="false" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="3" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="2" +querytype="protocol-valve" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Military Conflict: Vietnam" +engine="source" +glibc="2.15" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/vietnam" +executabledir="${serverfiles}" +executable="./srcds_run_x64" +servercfgdir="${systemdir}/cfg" +servercfg="${selfname}.cfg" +servercfgdefault="server.cfg" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 2405a4b3e..42b0bcfbd 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,java-21-openjdk mcb,libnsl +mcv mh mohaa,compat-libstdc++-33.i686 mta,ncurses-compat-libs,libxml2 @@ -82,7 +83,6 @@ opfor pc pc2 pmc,java-21-openjdk -ps,GConf2 pvkii pvr,libcxx pw @@ -109,12 +109,14 @@ sm,telnet,expect sof2 sol squad +squad44 st,libxml2 stn sven terraria tf tf2,libcurl.i686 +tf2c,libcurl.i686 tfc ti ts diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 069e8e437..7780ebf79 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,java-21-openjdk mcb,libnsl +mcv mh mohaa,compat-libstdc++-33.i686 mta,ncurses-compat-libs,libxml2 @@ -82,7 +83,6 @@ opfor pc pc2 pmc,java-21-openjdk -ps,GConf2 pvkii pvr,libcxx pw @@ -109,12 +109,14 @@ sm,telnet,expect sof2 sol squad +squad44 st,libxml2 stn sven terraria tf tf2,libcurl.i686 +tf2c,libcurl.i686 tfc ti ts diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index 39af5868d..c61fbf7d9 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,java-21-openjdk mcb,libnsl +mcv mh mohaa,compat-libstdc++-33.i686 mta,ncurses-libs,libxml2 @@ -82,7 +83,6 @@ opfor pc pc2 pmc,java-11-openjdk -ps,GConf2 pvkii pvr,libcxx pw @@ -109,12 +109,14 @@ sm,telnet,expect sof2 sol squad +squad44 st,libxml2 stn sven terraria tf tf2,libcurl.i686 +tf2c,libcurl.i686 tfc ti ts diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index bcaf1e31d..a9b0692b4 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,java-21-openjdk mcb,libnsl +mcv mh mohaa,compat-libstdc++-33.i686 mta,ncurses-compat-libs,libxml2 @@ -82,7 +83,6 @@ opfor pc pc2 pmc,java-17-openjdk -ps,GConf2 pvkii pvr,libcxx pw @@ -109,12 +109,14 @@ sm,telnet,expect sof2 sol squad +squad44 st,libxml2 stn sven terraria tf tf2,libcurl.i686 +tf2c,libcurl.i686 tfc ti ts diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 446a55ebb..2dcfe82b5 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,java-17-openjdk mcb,libnsl +mcv mh mohaa,compat-libstdc++-33.i686 mta,ncurses-compat-libs,libxml2 @@ -82,7 +83,6 @@ opfor pc pc2 pmc,java-17-openjdk -ps,GConf2 pvkii pvr,libcxx pw @@ -109,12 +109,14 @@ sm,telnet,expect sof2 sol squad +squad44 st,libxml2 stn sven terraria tf tf2,libcurl.i686 +tf2c,libcurl.i686 tfc ti ts diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index e0c6ea7e4..b4d0123ff 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -66,6 +66,7 @@ l4d l4d2 mc,openjdk-11-jre mcb +mcv mh mohaa,libstdc++5:i386 mta,libncursesw5,libxml2-utils @@ -115,6 +116,7 @@ sven,zlib1g:i386 terraria tf tf2,libcurl4-gnutls-dev:i386 +tf2c,libcurl4-gnutls-dev:i386 tfc ti ts diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 0d2652293..3e835e1d4 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,openjdk-17-jre mcb +mcv mh mohaa,libstdc++5:i386 mta,libncursesw5,libxml2-utils @@ -115,6 +116,7 @@ sven,zlib1g:i386 terraria tf tf2,libcurl4-gnutls-dev:i386 +tf2c,libcurl4-gnutls-dev:i386 tfc ti ts diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index e67a822b7..6c3dc59c7 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,openjdk-17-jre mcb +mcv mh mohaa,libstdc++5:i386 mta,libncursesw5,libxml2-utils @@ -115,6 +116,7 @@ sven,libssl3:i386,zlib1g:i386 terraria tf tf2,libcurl4-gnutls-dev:i386 +tf2c,libcurl4-gnutls-dev:i386 tfc ti ts diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index e7a622a7e..841be5a34 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,openjdk-25-jre mcb +mcv mh mohaa,libstdc++5:i386 mta,libncursesw5,libxml2-utils @@ -115,6 +116,7 @@ sven,libssl3:i386,zlib1g:i386 terraria tf tf2,libcurl4-gnutls-dev:i386 +tf2c,libcurl4-gnutls-dev:i386 tfc ti ts diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index a111c6800..a79b9ebaa 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -67,6 +67,7 @@ l4d l4d2 mc,openjdk-8-jre mcb +mcv mh mohaa,libstdc++5:i386 mta,libncursesw5,libxml2-utils @@ -115,6 +116,7 @@ sven,zlib1g:i386 terraria tf tf2,libcurl4-gnutls-dev:i386 +tf2c,libcurl4-gnutls-dev:i386 tfc ti ts diff --git a/lgsm/data/gameicons/mcv-icon.png b/lgsm/data/gameicons/mcv-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..fefcc23460df41173b4c4265a9f3e47018a67498 GIT binary patch literal 2334 zcmV+(3E}pMP){|8q>3VC9^G+t{kF@~ zMK#xj^$u)4oz7Cm<~U}XA(K*)fmi@DD~wVwDT>;VBuF_*kqadWI6)xBx>BVvByvon zO>Ln()v)|{?NXjdGgFtLwfFD$gXMKO-ME33NkkbTvroxNNCcUrWKNzj8wExQEl~@U zQiHcfWi2v7%G_5vR<%}(iY}Lv`AK2r?s|8yVNRvuyt_S~tyZ3-BXAsC77;OIU|>=t zLvRvuRTPs_X^|_UNnvb1WN%|Pkjm>twOXG{XND^ordm+2cI@{1`B%sEb0zY}=z0Fq_r$MO9V0 zD5VmLJ#obL$8G7c>cz3?jFM*`uNhU-Za@};#1Uo7Vw1%dWh<4JimW?MCd*2wG=viA zv|eHi_x%7VW*?FdG^^(Gxi+$GckQ+r?)`SN8m)+fze;AR>ZEi&GKZ98b;q8y6kuM?)JtGq22hpC@(MO_0nL0 z&a*6y=jxajyHssraWq2Iu}+qU!#MP$43u>gVpuK>wzgDJlRrJ3oKp4l`D2^yi&rmR zzWpgi???6?&YsP!_3Fet`P)zTwts)KZ5-t3!~0#@aQrpTz4yEO`-3S}G@*}rb}@feoWnq0uCzqgR&8N@*=Hb)NyqJCcn{PIG)~Z<- zCSpC+9*W+vv&o8-FoDs41jIfKQWuk=Ov{;YF=d}PgzWFT_af)&Os>*o(A{!2eg4^# zi^sFZdPm8u&hvvuV?%9kELH93#~4z!oLx@Nd*??NU8J(A2J3^$gZEWAZQ5I{pc}^| z{9I4PgvA6;iuL+ut5TPO#x}j%xbe_?$o2QT&D}6-$DAb`4hMupkQ8KTAcOWmQAVoj z)&96`4~;V0O+`%b81f_2FiHaZ)XoWfZ{vi$}93=Vw=&^zuXc!^`%VO^CvJj+_#( zkV!+L{nk?^Bl2Nr7iBfLjx|hcGhbhP`A?tLi`d0&T`pRe-ZrCJpNu#d&2dPztmg`8 zJbv`^kI&c5=f8aXYQulN9)ADLD~S?05FmgiV1tk&kG&mA&C_YQIA5GTI=T4xyygD- z=C*Nz-1%xf15>n3dvRH|hrLX5CDs8iJKubGbJ%70_WI@RNW;-QIy+-e`wyGL{SH&0 zoCGO_5WTl~?5e3;S8_R<{_%(F|Gjy?CjqrEs{i??(_cO-b+R;;#FM*2@#{ZtK$o#x z?L%-v?ko*H_YG$UI+BUgg}NXE#Ee9w!H8&cs=a8^np1GaXz`oYWS(8H+woceSE)b zUcI~DVa>S>vX~O4?lzCRFF%^ErMP+h1DE+1pFeb>{Oy1L4{>&xbHEqPy z-d$Z=y?F5SIk{{V14|W14ODKq+{$^_SN&v)z|;<`O|*CKOW#uKi={5+1Iab zcA!TVbcCFlBkB>09?Fp^q?Ce13IY=V015_TK*5jz$7onDG}YnQ6)67Yt1p*x?-#Rg zU%XsQ*Q!1}=5Dv^jseh6-?h{Vk%S&)=|yExWdIS55`nqg z6wA@EJ$thL@b>?BHu=M!zN>3r)$~IdlL1A3gfy%YS|O>ivg(IAY~Q9Q>&4kswm1 zW(j3L#V81wIH=^A8B$`F5rHv7W&ttzkU4-Bje+b^aj#t7*8gN;@wQ-EMdJef@YAG7(?2DxLyxc~qF07*qoM6N<$ Ef~gOJ-v9sr literal 0 HcmV?d00001 diff --git a/lgsm/data/gameicons/ps-icon.png b/lgsm/data/gameicons/ps-icon.png deleted file mode 100644 index afe81e82340b2e04a66a4487da79be395d144dc4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1216 zcmV;x1V8(UP);lyv|H@b~B2Jk~o$#Q~>DXj^_S7i)EPB=jBK)UDdc|P~) z2mgfE4=;dFa0&s!U?*Sz2so$?5(^FxfC&QtlMpG{EAgK;a(CD!C2SGUC=pCVVF~C; z#(r2?arfipR>>a6ar=;|q|+jrCAq0t1kn)rbbpF1I1+c$es5`W1z9y%Z!OwG2Ib5d zQi{oflGLHUdvA`1$483;&t?9+>O{^pD@=7$5|H?ya^{8_-F-c3#-9Dr=!QMpr*eV* z?e~Rg4-+tHQ{FXk@84ntA$>k3^OZiu-pR>W>*+2EN>Cz9>TG?9{bbH=Rc|Mqxc=X#C}`ceeyf-teI&QFUegY>)zXP`>A}ejXn_7Xm7`G>u=vT|nUqIHyqy3$g zZdM)x9o=%iub6S$7e%gwno2t?4P>w__q`6&>bf~r!rB)0H7dE9_ck^L=;DEv z_WB)+Cd0ipDlBWVt>np$`_YXNbe(E?LO77LJ~cTJubC=hZGa{qY`9X_e+0!5Q^{Py zZBvK5$=P*3>?VQPiSj$W!UX)&OBTh|qIo*y)3}L@!hdS6jE%V}2742$t8PQvB!Z7x zQY#`aQG4dq;ZKeSkL`-uedja=XsC-$nCc7;6q3F3 z*Z%st;dbzXGiSLceklh5VUl}$bYJbazwI>;>rTy0b1htJZ}4h%Yr1HW00O|)!1*&b z{v4=U!8kY^-jh?^wWZ3)XWR|~qBNA9G%u|cY5c*zbJCNMo_f8lV_Vs=UnQ7ifQ^Rl z_}`rJ*xy*^$~Fok4@aI%6|KwP_Xh-`oPtFR#+nOMx_?<-%gE6Iee&=PnmUtr8`Na5 zz;y`50BrlQJ$!lev{FsRaLqQ|kDGLB00t5vA18}>p&PR)|6951JC3HntbYx+4WjbSWWnpw>05UK#Gc7SNEipD! zF*iCeIXW{nD=;uRFfc@Fw(|f003~!qSaf7zbY(hiZ)9m^c>ppnGBYhPFfB1QR53R? eFgZFiH7hVMIxsLbHx5q#0000vG925{=gAW`89C~`Ddy4uON1M6+H~)XVX8|=`Rp-?C&Ud~lgb)%% z5g~*Sk|YTRf*`;^mSyzISeDHmz^*_bfc|Pc&pWdiW8`wV5JHNgz_g}mnx?^+<2V>F z3A!!RhNgbZ1WpCcR zSzcZ~b?OwuFdWALI8GUU*3zjkRBy+Q9lEZMj*hObuHL$JtEQ%=y1Lr7ZAxi>e}7(H zUMLijWtr#sqN1Y4#>UmvRZ3|j63KQg2m%lRV~pTmc9~J(=>)*g27-c z7BfwAcz9SJ3knKcE|;chv$M05(v_8!UAuPu#%YJyNEAhu zWi?H+EUTubCND3qwzjskw6wgu+~e__IB{Zqecd!oSX@_Ecj?k4pU=nhye!Mr)z!&l za(#WhzrP;UJQ<6{78Vxb@pvp2+t}DxT3X_H{^`@Fo12@Po15Wq z7-Kv)H)mPal`B`=Za37nwY9aXsw$OAg~MS%5FF~uvdpH_X@+4~mNg9H;>C+ko;)Fh z*tVTaCJPG-0pHJ`KQAmS1Ofp<2qA=JS-;=k-QDf?`%|gZ($dnyhYt)prKP2Aw;O=wIF3>p3WZcv)ph;u-Mgk~_Vo1Vx=tyTBqBuQcz#^HmaC@z;P7z`?kQdwDv5c2tay}i8;9y};2D$38# zFD@?b?(U|PLeF2md>L58A%s>|Rxrkki;KCrxzT8p=Xu+<{eC}Gp67W=X)>AQdH&3q zGqG6g@#Du=uU_rw=ulPFvaFVtmcxe+H#Ie>syaM8{OHl6w{PE0O-=cHKEp7!drc68 z7cX9DnpRR$Qdn5%@pyLb+$jh`I2?w4@p`?-jvZTETwGgQgOh?rrBW$E$iTorQ&ZD# zTEuZ2CkR3&lR*esmi6u1w}S@{y4~)wva)zQUQtm|RaK>F+W!6fp{=H-rUHS0$Kyc= zZES3KJRZX^Mn*<@dV1#P=Yjql$ALqT-k)s^MQ?9!A0Ho|pP#3cZf$LCY-|8Hkx1m+ zxpQ~!+%ZiPL?5P1)2y$rXBfu0f*fsjEMQaBz@P+R@R0vLqeKixBGU?7VQ{g3ILsK(a4zIFKlc+x5U0L(9QmSl!&*oKB|) z2M675cQ*M{RYeHhyLZodh`@KpUG`h#=Z*HaCd=~Z=qRPMqN2h{3#QJWKR+-qfU+Jt z|I&^eITDY@Z{EBa3jZb5%#(I1$D?4d)4UcGwt?AbHuHRvpdvj08_aFGqMD2m$;o?rIg nU;fNszoRe^4_@H^q`dzD5Wgm!a9kiv00000NkvXXu0mjf**A<+ literal 0 HcmV?d00001 diff --git a/lgsm/data/gameicons/tf2c-icon.png b/lgsm/data/gameicons/tf2c-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..f466347a186fad95ce446187b3c36c1c226c8970 GIT binary patch literal 2412 zcmV-y36u7TP)CY z3vP(S)HrL_|cE%jN3Ix;CarP8`vK?ex}>O){vp z6R8LNsEi@4kf@Y`h|@IH3iCV*gV7E_0YJ`K*9tio5pJ4>nNvzv!VvZ<$;Q^|$v400 zjyvx-{+i=4=12eFk*_@aAC-_Q9Jy-yrkieh?yFzjxqJY%8l#D594BjC)3l}JS}PH0 zhN`s&hLDnoAYm4cDU#v4?tbT6fAsc^tqoF`aM#u3+uQH?_4{A@`qyr3t_`6F zQlJ$8p8MaIg*k-cTDy68J(OW>Yw@mMz2}x&zxVM+{`k8up6j|55kXK|X<;a(5F*a= zY^`<9iAV_H*s)^|Km70wH=pQM+GXhH5|uGhaZY7<(0lKRFf(s%Z)$Ir;lQ`{4Y%C< z;DaALdewF*MHrlG5LHUWxrRa-o30HLOVS8NId$Lre)-sqTUM2llSL01K@vfhl=m(T zTxyKz$dMzpaxT$(8&e=vkKM5S-Ur{EN^G3t9HazeA;f`uEu(r0AOROkTv({7z4{aV^-&kCI_0jd!jnDkm-&*oS z#JL#dVh-A2Rprq?{QXzGdOOPu$bbuLA;;P4m7jj+sbN29tqB>w@2bu@7eesfi-@!K z%4_GuO{-I$KoF|+uG?Sk`Nn9ZVHnmoHo`n!cl_E@zw(RQM>aMOA5waubP=9_&HLZ| zn=k#(r7(>~1HSp{&KLtynb~T`sVHSCgOFyK0JGLMB|tPtnY2hw-nV@}TH{^g=M+jU zTI-dy^{vC*v16OU>dRmJcZG|RgE19vy=EmR0_}30-tt2yN%6}sUEI0Y_rsLa?6h&l z4+lXRqZBYC6pg5)QYoqJnlKJldqs{RR0c!@z?`#ho0OTEb;*%gTWhYp_L_%&<3Xf| zXrP#o!v4OWE&q1u0TI)Q;Gyi$^`Wvq;B?6&wI>q2S zzj<{1-ur*)V;}vawXPk9;Jhvnr*Zh;hu?F@owqyZw5DkoW8tw6I~Vpo{^;Z1dj8uA zP1|%aMsmIrCL*g<`^*=8*hFc8mhHUQ)=5)$^}?}nL|H6`^>+-e16~it`t#K zmsy&o$vHEpm_w;Wq;M_w-goN6_q;mH`^F<8G_7OK{qoYHbz$yLpFYh+n5%bf-}f}< zS*Q>JGheuH`RS)VABLnrmzWyoW0;Yu_3p(Nzgvn3V-;LGv^Gq=Z=6ESx#pP(%)%ey zqW|Qvzqt7F9#pNBo#LddBIBu)#K3LaBG8|H>d&8l{sm@sMhQm%A)=JZ?#{kejj$HP z!&^t1rbD1{n4NBo?tn2)>g!+o=4bx$>DF&Zt|5fB^C<_CQWZHx&ECP-_!VILI}d&2 z{I>_jhOC{_0aD6wzI161NsFqBwUuVEQbBPQ<%;M&)_rjGrT^ah-G@JdVwgEg0YxPX zf+hecr7*KGrWCQ(U$}7j0}p)Y%g;VnvuWJAp>BVtS7i2f_6gL+hBJn93JR$f1hypY z*S_+N4?OUpix>BeaU!6UsZ}iHHbTYegi+SZnoep>$1o)LO?dTiYn5 z=6SYWzyA8`&c5(p%*&Zj2VVODW#Nh&W+>foDq@28Bc7iv^64pzE3#V=2Y^wq&eONHH^)T%BujjsViOiz~Y`Ga|NaJC40`PLr`Q%nY+J zMp?zcxnxNIAXTdIjfnJ9K&;lgIVS|GjgB!kO#@WtoHjQP?e1P4=b#i;sALF$`f1FC zeP{5R#y5>)=31GEuK0;aX^3+H(AL@*M eNE1;A@&5oeRnKIuq;I Date: Fri, 24 Apr 2026 22:43:42 +0100 Subject: [PATCH 30/53] fix: support legacy game servers on older Ubuntu/Debian runners (#4903) * fix(workflows): support legacy game servers on older Ubuntu/Debian runners Multiple game servers have glibc compatibility requirements that prevent them from running on Ubuntu 24.04: - bfv, bf1942: Require Ubuntu <= 22.04 or Debian <= 12 (glibc 2.31) - btl, onset: Require Ubuntu <= 20.04 or Debian <= 11 (glibc 2.31) Changes: - Add runner field to details-check matrix generation - Map legacy servers to appropriate ubuntu-XX.04 LTS runners - Modern servers continue on ubuntu-latest (24.04) - Update details-check.yml to use dynamic runner from matrix This ensures all server tests pass in CI without breaking modern server testing on current GitHub Actions runners. * fix(workflows): run details-check on PRs and normalize ref resolution Details Check was not running for PR #4903 because the workflow only triggered on push to develop/workflow_dispatch. Also, pull_request refs (refs/pull/*) are not valid raw-content refs for GitHub downloads. Changes: - Trigger Details Check on pull_request to develop - Add LGSM_REF env resolved to PR head SHA or branch ref name - Use LGSM_REF for linuxgsm.sh download and LGSM_GITHUBBRANCH usage - Use LGSM_REF in matrix generation when fetching serverlist.csv This ensures legacy server jobs (bfv, bf1942, btl, onset) are included and executed during PR validation. * fix(workflows): run update-check on PRs and normalize ref resolution Apply the same PR-safe workflow behavior used in details-check: - Trigger update-check on pull_request to develop - Resolve LGSM_REF to PR head SHA or branch ref name - Use LGSM_REF for linuxgsm.sh download and LGSM_GITHUBBRANCH calls This ensures update-check validates PR changes instead of only running on develop pushes. * fix(check_deps): avoid false Debian version check on Ubuntu Ubuntu reports ID_LIKE=debian, which caused Debian upper-version checks to run on Ubuntu and incorrectly fail legacy titles on Ubuntu 22.04.x. Use distroid==debian for Debian limits in legacy compatibility guards so: - bf1942/bfv pass on Ubuntu 22.04.x as intended - btl/onset limits still apply correctly - Debian limits still apply on Debian only * fix(workflows): add PR trigger to version-check; replace archived action in docker trigger version-check.yml: - Add pull_request trigger targeting develop so version format is validated on PRs before merge trigger-docker-build.yml: - Replace archived convictional/trigger-workflow-and-wait@v1.6.5 with native gh CLI approach (trigger + watch run ID) - Uses GH_TOKEN env var with PERSONAL_ACCESS_TOKEN secret - gh workflow run dispatches the workflow; gh run watch polls for completion and exits non-zero on failure, preserving job dependencies * fix(workflows): use timestamp filter to reliably identify triggered run ID Using --limit 1 to find the run ID is a race condition if another run of the same workflow starts concurrently. Capture a timestamp before dispatching and pass --created >=${before} to gh run list so we always select the run we just triggered. * remove pr check --- .../details-check-generate-matrix.sh | 19 +++++++- .github/workflows/details-check.yml | 20 +++++---- .github/workflows/trigger-docker-build.yml | 44 ++++++++++++++----- .github/workflows/update-check.yml | 16 ++++--- lgsm/modules/check_deps.sh | 6 +-- 5 files changed, 74 insertions(+), 31 deletions(-) diff --git a/.github/workflows/details-check-generate-matrix.sh b/.github/workflows/details-check-generate-matrix.sh index 2c0803519..1093a46cf 100755 --- a/.github/workflows/details-check-generate-matrix.sh +++ b/.github/workflows/details-check-generate-matrix.sh @@ -1,6 +1,7 @@ #!/bin/bash -curl "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/lgsm/data/serverlist.csv" | grep -v '^[[:blank:]]*$' > serverlist.csv +ref="${LGSM_REF:-${GITHUB_REF#refs/heads/}}" +curl "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${ref}/lgsm/data/serverlist.csv" | grep -v '^[[:blank:]]*$' > serverlist.csv echo -n "{" > "shortnamearray.json" echo -n "\"include\":[" >> "shortnamearray.json" @@ -14,10 +15,26 @@ while read -r line; do export gamename distro=$(echo "$line" | awk -F, '{ print $4 }') export distro + # Legacy servers that require older Ubuntu/Debian versions due to glibc compatibility + case "${shortname}" in + bfv|bf1942) + # Requires Ubuntu <= 22.04 or Debian <= 12 (glibc 2.31 compatible) + runner="ubuntu-22.04" + ;; + btl|onset) + # Requires Ubuntu <= 20.04 or Debian <= 11 (glibc 2.31 compatible) + runner="ubuntu-20.04" + ;; + *) + runner="ubuntu-latest" + ;; + esac { echo -n "{"; echo -n "\"shortname\":"; echo -n "\"${shortname}\""; + echo -n ",\"runner\":"; + echo -n "\"${runner}\""; echo -n "},"; } >> "shortnamearray.json" done < <(tail -n +2 serverlist.csv) diff --git a/.github/workflows/details-check.yml b/.github/workflows/details-check.yml index aced7522d..856ab2d2a 100644 --- a/.github/workflows/details-check.yml +++ b/.github/workflows/details-check.yml @@ -17,6 +17,8 @@ jobs: create-matrix: if: github.repository_owner == 'GameServerManagers' runs-on: ubuntu-latest + env: + LGSM_REF: ${{ github.event.pull_request.head.sha || github.ref_name }} outputs: matrix: ${{ steps.set-matrix.outputs.matrix }} steps: @@ -37,14 +39,16 @@ jobs: if: github.repository_owner == 'GameServerManagers' needs: create-matrix continue-on-error: true - runs-on: ubuntu-latest + runs-on: ${{ matrix.runner }} + env: + LGSM_REF: ${{ github.event.pull_request.head.sha || github.ref_name }} strategy: matrix: ${{ fromJSON(needs.create-matrix.outputs.matrix) }} steps: - name: Download linuxgsm.sh - run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh"; chmod +x linuxgsm.sh + run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${LGSM_REF}/linuxgsm.sh"; chmod +x linuxgsm.sh - name: Install dependencies run: sudo apt-get install libxml2-utils jq @@ -53,10 +57,10 @@ jobs: run: mkdir -p serverfiles - name: Grab server - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./linuxgsm.sh ${{ matrix.shortname }}server + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./linuxgsm.sh ${{ matrix.shortname }}server - name: Enable developer mode - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server developer + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server developer - name: Generate servercfgname id: sets-servercfgname @@ -73,7 +77,7 @@ jobs: fi - name: Pre-load LinuxGSM - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server details + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server details - name: Display config run: | @@ -87,10 +91,10 @@ jobs: run: grep "startparameters" lgsm/config-default/config-lgsm/${{ matrix.shortname }}server/_default.cfg - name: Details - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server details + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server details - name: Detect details - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server parse-game-details + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server parse-game-details - name: Query Raw - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server query-raw + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server query-raw diff --git a/.github/workflows/trigger-docker-build.yml b/.github/workflows/trigger-docker-build.yml index 390123322..823592457 100644 --- a/.github/workflows/trigger-docker-build.yml +++ b/.github/workflows/trigger-docker-build.yml @@ -15,12 +15,22 @@ jobs: runs-on: ubuntu-latest steps: - name: Trigger Workflow and Wait (linuxgsm) - uses: convictional/trigger-workflow-and-wait@v1.6.5 - with: - owner: GameServerManagers - repo: docker-linuxgsm - github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - workflow_file_name: action-docker-publish.yml + env: + GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: | + before=$(date -u +%Y-%m-%dT%H:%M:%SZ) + gh workflow run action-docker-publish.yml --repo GameServerManagers/docker-linuxgsm + sleep 10 + run_id=$(gh run list \ + --workflow action-docker-publish.yml \ + --repo GameServerManagers/docker-linuxgsm \ + --created ">=${before}" \ + --limit 1 \ + --json databaseId \ + --jq '.[0].databaseId') + gh run watch "${run_id}" \ + --repo GameServerManagers/docker-linuxgsm \ + --exit-status trigger_build_docker-gameserver: if: github.repository_owner == 'GameServerManagers' @@ -29,9 +39,19 @@ jobs: runs-on: ubuntu-latest steps: - name: Trigger Workflow and Wait (gameserver) - uses: convictional/trigger-workflow-and-wait@v1.6.5 - with: - owner: GameServerManagers - repo: docker-gameserver - github_token: ${{ secrets.PERSONAL_ACCESS_TOKEN }} - workflow_file_name: action-docker-publish.yml + env: + GH_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }} + run: | + before=$(date -u +%Y-%m-%dT%H:%M:%SZ) + gh workflow run action-docker-publish.yml --repo GameServerManagers/docker-gameserver + sleep 10 + run_id=$(gh run list \ + --workflow action-docker-publish.yml \ + --repo GameServerManagers/docker-gameserver \ + --created ">=${before}" \ + --limit 1 \ + --json databaseId \ + --jq '.[0].databaseId') + gh run watch "${run_id}" \ + --repo GameServerManagers/docker-gameserver \ + --exit-status diff --git a/.github/workflows/update-check.yml b/.github/workflows/update-check.yml index 8863cedc7..ad1150f7b 100644 --- a/.github/workflows/update-check.yml +++ b/.github/workflows/update-check.yml @@ -16,6 +16,8 @@ jobs: update-check: if: github.repository_owner == 'GameServerManagers' runs-on: ubuntu-latest + env: + LGSM_REF: ${{ github.event.pull_request.head.sha || github.ref_name }} strategy: fail-fast: false @@ -24,30 +26,30 @@ jobs: steps: - name: Download linuxgsm.sh - run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${GITHUB_REF#refs/heads/}/linuxgsm.sh"; chmod +x linuxgsm.sh + run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${LGSM_REF}/linuxgsm.sh"; chmod +x linuxgsm.sh - name: Install dependencies run: sudo dpkg --add-architecture i386; sudo apt-get update; - name: Grab server - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./linuxgsm.sh ${{ matrix.shortname }}server + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./linuxgsm.sh ${{ matrix.shortname }}server - name: Enable developer mode - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server developer + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server developer - name: Insert steamuser if: matrix.shortname == 'jk2' run: echo -e "steamuser=\"${{ secrets.STEAMCMD_USER }}\"\nsteampass='${{ secrets.STEAMCMD_PASS }}'" > lgsm/config-lgsm/${{ matrix.shortname }}server/common.cfg - name: Install server - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server auto-install + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server auto-install - name: Check Update server - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server check-update + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server check-update - name: Update server - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server update + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server update - name: Force Update server if: matrix.shortname == 'css' - run: LGSM_GITHUBBRANCH="${GITHUB_REF#refs/heads/}" ./${{ matrix.shortname }}server force-update + run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server force-update diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 6d572fd40..3d4109e2c 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -362,7 +362,7 @@ if [ -n "${distrosupport}" ]; then fi # These titles are only supported up to Ubuntu 22.04 (Jammy) and Debian 12 (Bookworm). -if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "22.04"; } || { [ "${distroidlike}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "12"; }; then +if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "22.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "12"; }; then if [ "${shortname}" == "bf1942" ] || [ "${shortname}" == "bfv" ]; then fn_print_failure_nl "${gamename} is not supported on ${distroname} (requires Ubuntu <= 22.04 or Debian <= 12)." fn_script_log_fail "${gamename} is not supported on ${distroname}." @@ -370,8 +370,8 @@ if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" fi fi -# These titles are only supported up to Ubuntu 20.04 and Debian 11 (and Debian-like derivatives). -if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "20.04"; } || { [ "${distroidlike}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "11"; }; then +# These titles are only supported up to Ubuntu 20.04 and Debian 11. +if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "gt" "20.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "gt" "11"; }; then if [ "${shortname}" == "onset" ] || [ "${shortname}" == "btl" ]; then fn_print_failure_nl "${gamename} is not supported on ${distroname} (requires Ubuntu <= 20.04 or Debian <= 11)." fn_script_log_fail "${gamename} is not supported on ${distroname}." From 4fda9ab461406928326975688b47e08d43a21873 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 24 Apr 2026 22:47:31 +0100 Subject: [PATCH 31/53] chore(deps): bump dessant/lock-threads from 5 to 6 (#4864) Bumps [dessant/lock-threads](https://github.com/dessant/lock-threads) from 5 to 6. - [Release notes](https://github.com/dessant/lock-threads/releases) - [Changelog](https://github.com/dessant/lock-threads/blob/main/CHANGELOG.md) - [Commits](https://github.com/dessant/lock-threads/compare/v5...v6) --- updated-dependencies: - dependency-name: dessant/lock-threads dependency-version: '6' dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> Co-authored-by: Daniel Gibbs --- .github/workflows/lock.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml index 8a08284a4..a0a810172 100644 --- a/.github/workflows/lock.yml +++ b/.github/workflows/lock.yml @@ -15,7 +15,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Lock Threads - uses: dessant/lock-threads@v5 + uses: dessant/lock-threads@v6 with: github-token: ${{ secrets.GITHUB_TOKEN }} issue-comment: > From f48da4f3066cf401548cbdd2562420a959ef82c6 Mon Sep 17 00:00:00 2001 From: WildPenguin Date: Sun, 26 Apr 2026 14:19:52 +0300 Subject: [PATCH 32/53] papermc: add OpenJDK-25 (headless) dependency Dev builds of papermc will not work on older jre, albeit it's still in alpha/beta, some time in the future it will be the stable build. I have not noticed any issues running the stable build with jre-25. --- lgsm/data/ubuntu-24.04.csv | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 6f96fac7f..e9cdc2002 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -82,7 +82,7 @@ onset,libmariadb-dev opfor pc pc2 -pmc,openjdk-21-jre +pmc,openjdk-25-jre-headless pvkii pvr,libc++1 pw From 0862942d5481e94a89c2b407dc8e437f055c7e6b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 26 Apr 2026 18:22:41 +0000 Subject: [PATCH 33/53] fix(pmc): use openjdk-25-jre instead of headless variant, update vpmc to java 25 --- lgsm/data/ubuntu-24.04.csv | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index e9cdc2002..478d2b240 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -82,7 +82,7 @@ onset,libmariadb-dev opfor pc pc2 -pmc,openjdk-25-jre-headless +pmc,openjdk-25-jre pvkii pvr,libc++1 pw @@ -130,7 +130,7 @@ ut3 ut99 vh,libc6-dev,libatomic1,libpulse-dev vints,dotnet-runtime-8.0 -vpmc,openjdk-21-jre +vpmc,openjdk-25-jre vs wet wf From 0396f245910cf6fd5c4cb28617bfc5e490868726 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 26 Apr 2026 19:42:20 +0100 Subject: [PATCH 34/53] feat(deps): update Java deps to openjdk-25-jre and add Ubuntu 26.04 support (#4908) - ubuntu-24.04: update pz, rw, wmc to openjdk-25-jre - debian-13: update vpmc to openjdk-25-jre, fix wmc typo (openjdk21-jre -> openjdk-25-jre) - add ubuntu-26.04.csv with all Java deps on openjdk-25-jre --- lgsm/data/debian-13.csv | 4 +- lgsm/data/ubuntu-24.04.csv | 6 +- lgsm/data/ubuntu-26.04.csv | 141 +++++++++++++++++++++++++++++++++++++ 3 files changed, 146 insertions(+), 5 deletions(-) create mode 100644 lgsm/data/ubuntu-26.04.csv diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 841be5a34..a287d7835 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -130,11 +130,11 @@ ut3 ut99 vh,libc6-dev,libatomic1,libpulse-dev vints,dotnet-runtime-8.0 -vpmc,openjdk-21-jre +vpmc,openjdk-25-jre vs wet wf -wmc,openjdk21-jre +wmc,openjdk-25-jre wurm,xvfb xnt zmr diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index 478d2b240..f2578b9a8 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -86,7 +86,7 @@ pmc,openjdk-25-jre pvkii pvr,libc++1 pw -pz,openjdk-21-jre,rng-tools5 +pz,openjdk-25-jre,rng-tools5 q2 q3 q4 @@ -96,7 +96,7 @@ ricochet ro rtcw rust,lib32z1 -rw,openjdk-21-jre +rw,openjdk-25-jre samp sb sbots @@ -134,7 +134,7 @@ vpmc,openjdk-25-jre vs wet wf -wmc,openjdk-21-jre +wmc,openjdk-25-jre wurm,xvfb xnt zmr diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv new file mode 100644 index 000000000..f2578b9a8 --- /dev/null +++ b/lgsm/data/ubuntu-26.04.csv @@ -0,0 +1,141 @@ +all,bc,binutils,bsdmainutils,bzip2,ca-certificates,cpio,curl,distro-info,file,gzip,hostname,jq,lib32gcc-s1,lib32stdc++6,netcat-openbsd,pigz,python3,tar,tmux,unzip,util-linux,uuid-runtime,wget,xz-utils +steamcmd,lib32gcc-s1,lib32stdc++6,libsdl2-2.0-0:i386,steamcmd +ac +ahl +ahl2 +ark +arma3 +armar,libcurl4t64 +ats +av +bb +bb2,libcurl4-gnutls-dev:i386 +bd +bf1942 +bfv,libstdc++5:i386 +bmdm +bo +bs +bt,libicu-dev,dos2unix,libxml2-utils +btl +cc +ck,xvfb,libxi6 +cmw +cod,libstdc++5:i386 +cod2,libstdc++5:i386 +cod4 +coduo,libstdc++5:i386 +codwaw +col +cs +cs2 +cscz +csgo +css +ct +dab +dayz +dmc +dod +dodr +dods +doi +dst,libcurl4-gnutls-dev:i386 +dys +eco,libgdiplus +em +etl +ets2 +fctr +fof +gmod +hcu +hl2dm +hldm +hldms +hw,lib32z1 +hz +ins +inss +ios +jc2 +jc3 +jk2 +kf +kf2 +l4d +l4d2 +mc,openjdk-25-jre +mcb +mcv +mh +mohaa,libstdc++5:i386 +mta,libxml2-utils +nd +nec +nmrih +ns +ns2,speex +ns2c,speex:i386 +ohd +onset,libmariadb-dev +opfor +pc +pc2 +pmc,openjdk-25-jre +pvkii +pvr,libc++1 +pw +pz,openjdk-25-jre,rng-tools5 +q2 +q3 +q4 +ql +qw +ricochet +ro +rtcw +rust,lib32z1 +rw,openjdk-25-jre +samp +sb +sbots +scpsl,mono-complete +scpslsm,mono-complete +sdtd,telnet,expect,libxml2-utils +sf +sfc +sm,telnet,expect +sof2 +sol +squad +squad44 +st,libxml2-utils +stn +sven,zlib1g:i386 +terraria +tf +tf2,libcurl4-gnutls-dev:i386 +tf2c,libcurl4-gnutls-dev:i386 +tfc +ti +ts +ts3 +tu +tw +unt +ut +ut2k4 +ut3 +ut99 +vh,libc6-dev,libatomic1,libpulse-dev +vints,dotnet-runtime-8.0 +vpmc,openjdk-25-jre +vs +wet +wf +wmc,openjdk-25-jre +wurm,xvfb +xnt +zmr +zps From 094de9eb5cf4f28e23873900e45dc4c62b3a03be Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 26 Apr 2026 19:45:52 +0100 Subject: [PATCH 35/53] chore: synced file(s) with dgibbs64/repo-sync (#4904) * chore: synced local '.github/' with remote 'general/.github/' * chore: synced local './' with remote 'bash/' --------- Co-authored-by: unknown --- .devcontainer/devcontainer.json | 56 +++++++++++------------ .github/workflows/action-super-linter.yml | 6 +-- .prettierrc.json | 2 +- .vscode/extensions.json | 20 ++++---- 4 files changed, 41 insertions(+), 43 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 32c844ac7..506b50754 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,30 +1,30 @@ { - "name": "BASH Dev Container", - "image": "mcr.microsoft.com/devcontainers/base:ubuntu", - "features": { - "ghcr.io/devcontainers-community/npm-features/prettier:1": { - "plugins": "prettier-plugin-sh" - }, - "ghcr.io/devcontainers-extra/features/actionlint:1": {}, - "ghcr.io/devcontainers-extra/features/checkov:1": {}, - "ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {}, - "ghcr.io/devcontainers-extra/features/shellcheck:1": {}, - "ghcr.io/devcontainers-extra/features/yamllint:2": {}, - "ghcr.io/devcontainers/features/github-cli:1": {} - }, - "customizations": { - "vscode": { - "extensions": [ - "DavidAnson.vscode-markdownlint", - "editorconfig.editorconfig", - "esbenp.prettier-vscode", - "github.vscode-github-actions", - "GitHub.vscode-pull-request-github", - "redhat.vscode-yaml", - "timonwong.shellcheck", - "yzhang.markdown-all-in-one" - ] - } - }, - "postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template" + "name": "BASH Dev Container", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers-community/npm-features/prettier:1": { + "plugins": "prettier-plugin-sh" + }, + "ghcr.io/devcontainers-extra/features/actionlint:1": {}, + "ghcr.io/devcontainers-extra/features/checkov:1": {}, + "ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {}, + "ghcr.io/devcontainers-extra/features/shellcheck:1": {}, + "ghcr.io/devcontainers-extra/features/yamllint:2": {}, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "DavidAnson.vscode-markdownlint", + "editorconfig.editorconfig", + "esbenp.prettier-vscode", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "redhat.vscode-yaml", + "timonwong.shellcheck", + "yzhang.markdown-all-in-one" + ] + } + }, + "postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template" } diff --git a/.github/workflows/action-super-linter.yml b/.github/workflows/action-super-linter.yml index e2755e20a..31b2fa949 100644 --- a/.github/workflows/action-super-linter.yml +++ b/.github/workflows/action-super-linter.yml @@ -27,9 +27,9 @@ jobs: - name: Checkout code uses: actions/checkout@v6 with: - # Full clone required so super-linter can resolve GITHUB_BEFORE_SHA. + # super-linter needs the full git history to get the + # list of files that changed across commits fetch-depth: 0 - fetch-tags: false persist-credentials: false - name: Install Prettier plugins (for summary formatting) @@ -41,7 +41,6 @@ jobs: env: # To report GitHub Actions status checks GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - DEFAULT_BRANCH: ${{ github.ref_name }} VALIDATE_BIOME_FORMAT: false VALIDATE_BIOME_LINT: false VALIDATE_GITHUB_ACTIONS_ZIZMOR: false @@ -49,7 +48,6 @@ jobs: VALIDATE_JSON_PRETTIER: false VALIDATE_MARKDOWN_PRETTIER: false VALIDATE_NATURAL_LANGUAGE: false - VALIDATE_PYTHON_RUFF_FORMAT: false VALIDATE_SHELL_SHFMT: false VALIDATE_TRIVY: false VALIDATE_YAML_PRETTIER: false diff --git a/.prettierrc.json b/.prettierrc.json index 1902f8021..02d542d50 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,3 +1,3 @@ { - "plugins": ["prettier-plugin-sh"] + "plugins": ["prettier-plugin-sh"] } diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 5c06a83bf..d31b65dd2 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,12 +1,12 @@ { - "recommendations": [ - "DavidAnson.vscode-markdownlint", - "editorconfig.editorconfig", - "esbenp.prettier-vscode", - "github.vscode-github-actions", - "GitHub.vscode-pull-request-github", - "redhat.vscode-yaml", - "timonwong.shellcheck", - "yzhang.markdown-all-in-one" - ] + "recommendations": [ + "DavidAnson.vscode-markdownlint", + "editorconfig.editorconfig", + "esbenp.prettier-vscode", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "redhat.vscode-yaml", + "timonwong.shellcheck", + "yzhang.markdown-all-in-one" + ] } From f7a1258b58a30cde8f55c50e5ee8e43f3297aaf3 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 26 Apr 2026 18:57:39 +0000 Subject: [PATCH 36/53] fix(jbep3): add distro deps entries and game icon --- .../config-lgsm/jbep3server/_default.cfg | 198 ++++++++++++++++++ lgsm/data/almalinux-8.csv | 1 + lgsm/data/almalinux-9.csv | 1 + lgsm/data/centos-7.csv | 1 + lgsm/data/centos-8.csv | 1 + lgsm/data/centos-9.csv | 1 + lgsm/data/debian-10.csv | 1 + lgsm/data/debian-11.csv | 1 + lgsm/data/debian-12.csv | 1 + lgsm/data/debian-13.csv | 1 + lgsm/data/debian-9.csv | 1 + lgsm/data/gameicons/jbep3-icon.png | Bin 0 -> 400 bytes lgsm/data/rhel-7.csv | 1 + lgsm/data/rhel-8.csv | 1 + lgsm/data/rhel-9.csv | 1 + lgsm/data/rocky-8.csv | 1 + lgsm/data/rocky-9.csv | 1 + lgsm/data/serverlist.csv | 2 +- lgsm/data/ubuntu-16.04.csv | 1 + lgsm/data/ubuntu-18.04.csv | 1 + lgsm/data/ubuntu-20.04.csv | 1 + lgsm/data/ubuntu-22.04.csv | 1 + lgsm/data/ubuntu-23.04.csv | 1 + lgsm/data/ubuntu-23.10.csv | 1 + lgsm/data/ubuntu-24.04.csv | 1 + lgsm/data/ubuntu-26.04.csv | 1 + 26 files changed, 222 insertions(+), 1 deletion(-) create mode 100644 lgsm/config-default/config-lgsm/jbep3server/_default.cfg create mode 100644 lgsm/data/gameicons/jbep3-icon.png diff --git a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg new file mode 100644 index 000000000..2036d3522 --- /dev/null +++ b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg @@ -0,0 +1,198 @@ +################################## +######## Default Settings ######## +################################## +# DO NOT EDIT, ANY CHANGES WILL BE OVERWRITTEN! +# Copy settings from here and use them in either: +# common.cfg - applies settings to every instance. +# [instance].cfg - applies settings to a specific instance. + +#### Game Server Settings #### + +## Predefined Parameters | https://docs.linuxgsm.com/configuration/start-parameters +ip="0.0.0.0" +port="27015" +clientport="27005" +sourcetvport="27020" +defaultmap="crossfire" +maxplayers="24" + +## Server Parameters | https://docs.linuxgsm.com/configuration/start-parameters#additional-parameters +startparameters="-game jbep3 -strictportbind -ip ${ip} -port ${port} +clientport ${clientport} +tv_port ${sourcetvport} +map ${defaultmap} +servercfgfile ${servercfg} -maxplayers ${maxplayers}" + +#### LinuxGSM Settings #### + +## LinuxGSM Stats +# Send useful stats to LinuxGSM developers. +# https://docs.linuxgsm.com/configuration/linuxgsm-stats +# (on|off) +stats="off" + +## Notification Alerts +# (on|off) + +# Display IP | https://docs.linuxgsm.com/alerts#display-ip +displayip="" + +# More info | https://docs.linuxgsm.com/alerts#more-info +postalert="off" + +# Alert on Start/Stop/Restart +statusalert="off" + +# Discord Alerts | https://docs.linuxgsm.com/alerts/discord +discordalert="off" +discordwebhook="webhook" + +# Email Alerts | https://docs.linuxgsm.com/alerts/email +emailalert="off" +email="email@example.com" +emailfrom="" + +# Gotify Alerts | https://docs.linuxgsm.com/alerts/gotify +gotifyalert="off" +gotifytoken="token" +gotifywebhook="webhook" + +# IFTTT Alerts | https://docs.linuxgsm.com/alerts/ifttt +iftttalert="off" +ifttttoken="accesstoken" +iftttevent="linuxgsm_alert" + +# ntfy Alerts | https://docs.linuxgsm.com/alerts/ntfy +ntfyalert="off" +ntfytopic="LinuxGSM" +ntfyserver="https://ntfy.sh" +ntfytoken="" +ntfyusername="" +ntfypassword="" +ntfypriority="" +ntfytags="" + +# Pushbullet Alerts | https://docs.linuxgsm.com/alerts/pushbullet +pushbulletalert="off" +pushbullettoken="accesstoken" +channeltag="" + +# Pushover Alerts | https://docs.linuxgsm.com/alerts/pushover +pushoveralert="off" +pushovertoken="accesstoken" +pushoveruserkey="userkey" + +# Rocket.Chat Alerts | https://docs.linuxgsm.com/alerts/rocket.chat +rocketchatalert="off" +rocketchatwebhook="webhook" + +# Slack Alerts | https://docs.linuxgsm.com/alerts/slack +slackalert="off" +slackwebhook="webhook" + +# Telegram Alerts | https://docs.linuxgsm.com/alerts/telegram +# You can add a custom cURL string eg proxy (useful in Russia) in "curlcustomstring". +# For example "--socks5 ipaddr:port" for socks5 proxy see more in "curl --help all". +telegramapi="api.telegram.org" +telegramalert="off" +telegramtoken="accesstoken" +telegramchatid="" +telegramthreadid="" +telegramsilentnotification="false" +curlcustomstring="" + +## Updating | https://docs.linuxgsm.com/commands/update +updateonstart="off" + +## Backup | https://docs.linuxgsm.com/commands/backup +maxbackups="4" +maxbackupdays="30" +stoponbackup="on" + +## Logging | https://docs.linuxgsm.com/features/logging +consolelogging="on" +logdays="7" + +## Monitor | https://docs.linuxgsm.com/commands/monitor +# Query delay time +querydelay="1" + +## ANSI Colors | https://docs.linuxgsm.com/features/ansi-colors +ansi="on" + +#### Advanced Settings #### + +## Message Display Time | https://docs.linuxgsm.com/features/message-display-time +sleeptime="0.5" + +## SteamCMD Settings | https://docs.linuxgsm.com/steamcmd +# Server appid +appid="869800" +steamcmdforcewindows="no" +# SteamCMD Branch | https://docs.linuxgsm.com/steamcmd/branch +branch="" +betapassword="" +# Master Server | https://docs.linuxgsm.com/steamcmd/steam-master-server +steammaster="true" + +## Stop Mode | https://docs.linuxgsm.com/features/stop-mode +# 1: tmux kill +# 2: CTRL+c +# 3: quit +# 4: quit 120s +# 5: stop +# 6: q +# 7: exit +# 8: 7 Days to Die +# 9: GoldSrc +# 10: Avorion +# 11: end +stopmode="3" + +## Query mode +# 1: session only +# 2: gamedig (gsquery fallback) +# 3: gamedig +# 4: gsquery +# 5: tcp +querymode="2" +querytype="protocol-valve" + +## Console type +consoleverbose="yes" +consoleinteract="yes" + +## Game Server Details +# Do not edit +gamename="Jabroni Brawl: Episode 3" +engine="source" +glibc="2.3.6" + +#### Directories #### +# Edit with care + +## Game Server Directories +systemdir="${serverfiles}/jbep3" +executabledir="${serverfiles}" +executable="./srcds_run.sh" +servercfgdir="${systemdir}/cfg" +servercfg="${selfname}.cfg" +servercfgdefault="server.cfg" +servercfgfullpath="${servercfgdir}/${servercfg}" + +## Backup Directory +backupdir="${lgsmdir}/backup" + +## Logging Directories +[ -n "${LGSM_LOGDIR}" ] && logdir="${LGSM_LOGDIR}" || logdir="${rootdir}/log" +gamelogdir="${systemdir}/logs" +lgsmlogdir="${logdir}/script" +consolelogdir="${logdir}/console" +lgsmlog="${lgsmlogdir}/${selfname}-script.log" +consolelog="${consolelogdir}/${selfname}-console.log" +alertlog="${lgsmlogdir}/${selfname}-alert.log" +postdetailslog="${lgsmlogdir}/${selfname}-postdetails.log" + +## Logs Naming +lgsmlogdate="${lgsmlogdir}/${selfname}-script-$(date '+%Y-%m-%d-%H:%M:%S').log" +consolelogdate="${consolelogdir}/${selfname}-console-$(date '+%Y-%m-%d-%H:%M:%S').log" + +## Log Parameters +logtimestamp="off" +logtimestampformat="%Y-%m-%d %H:%M:%S" diff --git a/lgsm/data/almalinux-8.csv b/lgsm/data/almalinux-8.csv index 42b0bcfbd..e02ca7858 100644 --- a/lgsm/data/almalinux-8.csv +++ b/lgsm/data/almalinux-8.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/almalinux-9.csv b/lgsm/data/almalinux-9.csv index 7780ebf79..5a6d996e7 100644 --- a/lgsm/data/almalinux-9.csv +++ b/lgsm/data/almalinux-9.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/centos-7.csv b/lgsm/data/centos-7.csv index c61fbf7d9..c5632722e 100644 --- a/lgsm/data/centos-7.csv +++ b/lgsm/data/centos-7.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/centos-8.csv b/lgsm/data/centos-8.csv index a9b0692b4..0b0b766d0 100644 --- a/lgsm/data/centos-8.csv +++ b/lgsm/data/centos-8.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/centos-9.csv b/lgsm/data/centos-9.csv index 2dcfe82b5..fd9c0fa39 100644 --- a/lgsm/data/centos-9.csv +++ b/lgsm/data/centos-9.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/debian-10.csv b/lgsm/data/debian-10.csv index b4d0123ff..5b8d73a06 100644 --- a/lgsm/data/debian-10.csv +++ b/lgsm/data/debian-10.csv @@ -57,6 +57,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/debian-11.csv b/lgsm/data/debian-11.csv index 3e835e1d4..adba97d27 100644 --- a/lgsm/data/debian-11.csv +++ b/lgsm/data/debian-11.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 6c3dc59c7..2da22f88c 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index a287d7835..401cf281c 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/debian-9.csv b/lgsm/data/debian-9.csv index a79b9ebaa..c0e990961 100644 --- a/lgsm/data/debian-9.csv +++ b/lgsm/data/debian-9.csv @@ -58,6 +58,7 @@ hz ins inss ios +jbep3 jc2 jc3 jk2 diff --git a/lgsm/data/gameicons/jbep3-icon.png b/lgsm/data/gameicons/jbep3-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..609a0345f36fd0fe211d0d2f656f048c821b2a3d GIT binary patch literal 400 zcmV;B0dM|^P)U>LPv)Phk9hOGtN)lFvlMxQ=^_Dzn2b0Jdy{{8#>^~=qBcjm2Ja{bON z{1z}VGBDsm5P;16^!c+xn2%>%$i-_{%=C?VYnpjDx$v04h{pm3R11)~zkdBXb>S=n z0|Pe~w}OluehUc40V4*Njg`&JzzE`@$Il)!QW(j|3ix<=_pRCjVgLXCf6lT6U%!53 zq;4Fzg!yBq#x^#A|=qoMA|Eb3|QQj%AC u`1sL*Bm38FUQeL~j5ed~qEQP*EdT&Sc5W~td^U0b0000 Date: Sat, 2 May 2026 16:57:56 +0100 Subject: [PATCH 37/53] feat(bb): add BrainBread server update functionality (#4912) * feat(bb): add BrainBread server update functionality * Implemented `update_bb.sh` to handle updates for BrainBread servers. * Integrated new update checks in `command_check_update.sh` and `command_update.sh`. * Updated `install_server_files.sh` to include BrainBread server installation logic. Co-authored-by: Copilot * feat(bb): enhance BrainBread update process * Updated `fn_update_dl` to use `remotebuildhash` for file integrity. * Added handling for missing `remotebuildhash` to default to "nohash". * Included `update_steamcmd.sh` call to ensure both Steam app and GitHub package updates are performed. Co-authored-by: Copilot * fix(steamcmd): ensure core HL1 files are present after appid 90 update * Added checks to verify the presence of core HL1 files after updating appid 90. * If files are missing, an update is forced and errors are logged. * Exits the script if files are still missing after the retry. * fix(steamcmd): update error messages for GoldSrc engine * Changed appid 90 references to GoldSrc for clarity. * Updated error messages to reflect the correct engine context. * Ensures users are informed about missing core HL1 files after GoldSrc updates. Co-authored-by: Copilot * feat(serverlist): add Military Conflict: Vietnam server entry * Introduced new server entry for `Military Conflict: Vietnam` in `serverlist.csv`. * Enhances the variety of game servers available for users. --------- Co-authored-by: Copilot --- lgsm/data/serverlist.csv | 1 + lgsm/modules/command_check_update.sh | 2 + lgsm/modules/command_update.sh | 2 + lgsm/modules/core_dl.sh | 6 + lgsm/modules/core_modules.sh | 5 + lgsm/modules/core_steamcmd.sh | 17 +++ lgsm/modules/install_server_files.sh | 13 +- lgsm/modules/update_bb.sh | 175 +++++++++++++++++++++++++++ 8 files changed, 212 insertions(+), 9 deletions(-) create mode 100644 lgsm/modules/update_bb.sh diff --git a/lgsm/data/serverlist.csv b/lgsm/data/serverlist.csv index 382eabbaf..3ddc013c3 100644 --- a/lgsm/data/serverlist.csv +++ b/lgsm/data/serverlist.csv @@ -67,6 +67,7 @@ l4d,l4dserver,Left 4 Dead,ubuntu-24.04 l4d2,l4d2server,Left 4 Dead 2,ubuntu-24.04 mc,mcserver,Minecraft,ubuntu-24.04 mcb,mcbserver,Minecraft Bedrock,ubuntu-24.04 +mcv,mcvserver,Military Conflict: Vietnam,ubuntu-24.04 mh,mhserver,MORDHAU,ubuntu-24.04 mohaa,mohaaserver,Medal of Honor: Allied Assault,ubuntu-24.04 mta,mtaserver,Multi Theft Auto,ubuntu-24.04 diff --git a/lgsm/modules/command_check_update.sh b/lgsm/modules/command_check_update.sh index 6e429512a..93a770e79 100755 --- a/lgsm/modules/command_check_update.sh +++ b/lgsm/modules/command_check_update.sh @@ -30,6 +30,8 @@ elif [ "${shortname}" == "jk2" ]; then update_jk2.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh +elif [ "${shortname}" == "bb" ]; then + update_bb.sh elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then diff --git a/lgsm/modules/command_update.sh b/lgsm/modules/command_update.sh index 996d402a4..a7cfc1b12 100755 --- a/lgsm/modules/command_update.sh +++ b/lgsm/modules/command_update.sh @@ -31,6 +31,8 @@ elif [ "${shortname}" == "jk2" ]; then update_jk2.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh +elif [ "${shortname}" == "bb" ]; then + update_bb.sh elif [ "${shortname}" == "ut99" ]; then update_ut99.sh elif [ "${shortname}" == "xnt" ]; then diff --git a/lgsm/modules/core_dl.sh b/lgsm/modules/core_dl.sh index 4730c0cff..c3194a915 100755 --- a/lgsm/modules/core_dl.sh +++ b/lgsm/modules/core_dl.sh @@ -139,6 +139,12 @@ fn_dl_steamcmd() { fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download server files" fn_script_log_fail "${commandaction} ${selfname}: ${remotelocation}: Not enough disk space to download server files" core_exit.sh + # Invalid platform for app/update request. + elif [ -n "$(grep -i "Invalid platform" "${steamcmdlog}" | tail -1)" ]; then + fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Invalid platform for AppID ${appid}" + fn_print_nl "Check steamcmdforcewindows setting and system architecture (x86_64 required for most servers)" + fn_script_log_fail "${commandaction} ${selfname}: ${remotelocation}: Invalid platform for AppID ${appid}" + core_exit.sh # Need tp purchase game. elif [ -n "$(grep "No subscription" "${steamcmdlog}" | tail -1)" ]; then fn_print_failure_nl "${commandaction} ${selfname}: ${remotelocation}: Steam account does not have a license for the required game" diff --git a/lgsm/modules/core_modules.sh b/lgsm/modules/core_modules.sh index 10d408449..ce1a6f6d4 100755 --- a/lgsm/modules/core_modules.sh +++ b/lgsm/modules/core_modules.sh @@ -710,6 +710,11 @@ update_ut99.sh() { fn_fetch_module } +update_bb.sh() { + modulefile="${FUNCNAME[0]}" + fn_fetch_module +} + update_vints.sh() { modulefile="${FUNCNAME[0]}" fn_fetch_module diff --git a/lgsm/modules/core_steamcmd.sh b/lgsm/modules/core_steamcmd.sh index d265f577d..463a1f7da 100755 --- a/lgsm/modules/core_steamcmd.sh +++ b/lgsm/modules/core_steamcmd.sh @@ -427,4 +427,21 @@ fn_check_steamcmd_appmanifest() { fn_dl_steamcmd fi fi + + # GoldSrc can occasionally report success while core HL1 files are incomplete. + if [ "${engine}" == "goldsrc" ]; then + if [ ! -f "${serverfiles}/hlds_run" ] || [ ! -f "${serverfiles}/engine_i486.so" ] || [ ! -d "${serverfiles}/valve" ]; then + fn_print_error_nl "Core HL1 files missing after GoldSrc update" + fn_script_log_error "Core HL1 files missing after GoldSrc update" + fn_print_info_nl "Forcing update to correct issue" + fn_script_log_info "Forcing update to correct issue" + fn_dl_steamcmd + + if [ ! -f "${serverfiles}/hlds_run" ] || [ ! -f "${serverfiles}/engine_i486.so" ] || [ ! -d "${serverfiles}/valve" ]; then + fn_print_fail_nl "Core HL1 files are still missing after retry" + fn_script_log_fail "Core HL1 files are still missing after retry" + core_exit.sh + fi + fi + fi } diff --git a/lgsm/modules/install_server_files.sh b/lgsm/modules/install_server_files.sh index 8a993b45c..e5f10739d 100755 --- a/lgsm/modules/install_server_files.sh +++ b/lgsm/modules/install_server_files.sh @@ -32,14 +32,7 @@ fn_install_server_files() { run="norun" force="noforce" md5="e3b4962cdd9d41e23c6fed65101bccde" - elif [ "${shortname}" == "bb" ]; then - remote_fileurl="http://linuxgsm.download/BrainBread/brainbread-v1.2-linuxserver.tar.xz" - local_filedir="${tmpdir}" - local_filename="brainbread-v1.2-linuxserver.tar.xz" - chmodx="nochmodx" - run="norun" - force="noforce" - md5="55f227183b736397806d5b6db6143f15" + elif [ "${shortname}" == "cod" ]; then remote_fileurl="http://linuxgsm.download/CallOfDuty/cod-lnxded-1.5b-full.tar.xz" local_filedir="${tmpdir}" @@ -267,6 +260,8 @@ elif [ "${shortname}" == "jk2" ]; then update_jk2.sh elif [ "${shortname}" == "vints" ]; then update_vints.sh +elif [ "${shortname}" == "bb" ]; then + update_bb.sh elif [ "${shortname}" == "ut99" ]; then fn_install_server_files update_ut99.sh @@ -274,7 +269,7 @@ elif [ "${shortname}" == "xnt" ]; then update_xnt.sh elif [ "${shortname}" == "etl" ]; then update_etl.sh -elif [ -z "${appid}" ] || [ "${shortname}" == "ahl" ] || [ "${shortname}" == "bb" ] || [ "${shortname}" == "q4" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "sfc" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "vs" ] || [ "${shortname}" == "zmr" ]; then +elif [ -z "${appid}" ] || [ "${shortname}" == "ahl" ] || [ "${shortname}" == "q4" ] || [ "${shortname}" == "ns" ] || [ "${shortname}" == "sfc" ] || [ "${shortname}" == "ts" ] || [ "${shortname}" == "vs" ] || [ "${shortname}" == "zmr" ]; then if [ "${shortname}" == "ut" ]; then install_eula.sh fi diff --git a/lgsm/modules/update_bb.sh b/lgsm/modules/update_bb.sh new file mode 100644 index 000000000..1f2f12ce8 --- /dev/null +++ b/lgsm/modules/update_bb.sh @@ -0,0 +1,175 @@ +#!/bin/bash +# LinuxGSM update_bb.sh module +# Author: Daniel Gibbs +# Contributors: https://linuxgsm.com/contrib +# Website: https://linuxgsm.com +# Description: Handles updating of BrainBread servers. + +moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" + +fn_update_dl() { + # Download and extract files to serverfiles. + fn_fetch_file "${remotebuildurl}" "" "" "" "${tmpdir}" "${remotebuildfilename}" "nochmodx" "norun" "force" "${remotebuildhash}" + fn_dl_extract "${tmpdir}" "${remotebuildfilename}" "${serverfiles}" + echo "${remotebuild}" > "${serverfiles}/build.txt" + fn_clear_tmp +} + +fn_update_localbuild() { + # Gets local build info. + fn_print_dots "Checking local build: ${remotelocation}" + # Uses build file to get local build. + localbuild=$(head -n 1 "${serverfiles}/build.txt" 2> /dev/null) + if [ -z "${localbuild}" ]; then + fn_print_error "Checking local build: ${remotelocation}: missing local build info" + fn_script_log_error "Missing local build info" + fn_script_log_error "Set localbuild to 0" + localbuild="0" + else + fn_print_ok "Checking local build: ${remotelocation}" + fn_script_log_pass "Checking local build" + fi +} + +fn_update_remotebuild() { + # Gets remote build info. + apiurl="https://api.github.com/repos/IronOak-Studios/BrainBread/releases/latest" + remotebuildresponse=$(curl -s "${apiurl}") + remotebuildfilename=$(echo "${remotebuildresponse}" | jq -r '.assets[] | select(.name | test("linuxserver\\.tar\\.gz$")) | .name' | head -n 1) + remotebuildurl=$(echo "${remotebuildresponse}" | jq -r '.assets[] | select(.name | test("linuxserver\\.tar\\.gz$")) | .browser_download_url' | head -n 1) + remotebuildhash=$(echo "${remotebuildresponse}" | jq -r '.assets[] | select(.name | test("linuxserver\\.tar\\.gz$")) | .digest' | sed 's/^sha256://g' | head -n 1) + remotebuild=$(echo "${remotebuildresponse}" | jq -r '.tag_name') + if [ -z "${remotebuildhash}" ] || [ "${remotebuildhash}" == "null" ]; then + remotebuildhash="nohash" + fi + + if [ "${firstcommandname}" != "INSTALL" ]; then + fn_print_dots "Checking remote build: ${remotelocation}" + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ] || [ -z "${remotebuildurl}" ] || [ "${remotebuildurl}" == "null" ] || [ -z "${remotebuildfilename}" ] || [ "${remotebuildfilename}" == "null" ]; then + fn_print_fail "Checking remote build: ${remotelocation}" + fn_script_log_fail "Checking remote build" + core_exit.sh + else + fn_print_ok "Checking remote build: ${remotelocation}" + fn_script_log_pass "Checking remote build" + fi + else + # Checks if remotebuild variable has been set. + if [ -z "${remotebuild}" ] || [ "${remotebuild}" == "null" ] || [ -z "${remotebuildurl}" ] || [ "${remotebuildurl}" == "null" ] || [ -z "${remotebuildfilename}" ] || [ "${remotebuildfilename}" == "null" ]; then + fn_print_failure "Unable to get remote build" + fn_script_log_fail "Unable to get remote build" + core_exit.sh + fi + fi +} + +fn_update_compare() { + fn_print_dots "Checking for update: ${remotelocation}" + # Update has been found or force update. + if [ "${localbuild}" != "${remotebuild}" ] || [ "${forceupdate}" == "1" ]; then + # Create update lockfile. + date '+%s' > "${lockdir:?}/update.lock" + fn_print_ok_nl "Checking for update: ${remotelocation}" + fn_print "\n" + fn_print_nl "${bold}${underline}Update${default} available" + fn_print_nl "* Local build: ${red}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuildhash: ${remotebuildhash}" + fn_print_nl "* remotebuild: ${remotebuild}" + fi + fn_print "\n" + fn_script_log_info "Update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + fn_script_log_info "${localbuild} > ${remotebuild}" + + if [ "${commandname}" == "UPDATE" ]; then + date +%s > "${lockdir:?}/last-updated.lock" + unset updateonstart + check_status.sh + # If server stopped. + if [ "${status}" == "0" ]; then + fn_update_dl + if [ "${localbuild}" == "0" ]; then + exitbypass=1 + command_start.sh + fn_firstcommand_reset + exitbypass=1 + fn_sleep_time_5 + command_stop.sh + fn_firstcommand_reset + fi + # If server started. + else + fn_print_restart_warning + exitbypass=1 + command_stop.sh + fn_firstcommand_reset + exitbypass=1 + fn_update_dl + exitbypass=1 + command_start.sh + fn_firstcommand_reset + fi + unset exitbypass + alert="update" + elif [ "${commandname}" == "CHECK-UPDATE" ]; then + alert="check-update" + fi + alert.sh + else + fn_print_ok_nl "Checking for update: ${remotelocation}" + fn_print "\n" + fn_print_nl "${bold}${underline}No update${default} available" + fn_print_nl "* Local build: ${green}${localbuild}${default}" + fn_print_nl "* Remote build: ${green}${remotebuild}${default}" + if [ -n "${branch}" ]; then + fn_print_nl "* Branch: ${branch}" + fi + fn_print "\n" + fn_script_log_info "No update available" + fn_script_log_info "Local build: ${localbuild}" + fn_script_log_info "Remote build: ${remotebuild}" + if [ -n "${branch}" ]; then + fn_script_log_info "Branch: ${branch}" + fi + if [ -f "${rootdir}/.dev-debug" ]; then + fn_print_nl "Remote build info" + fn_print_nl "* apiurl: ${apiurl}" + fn_print_nl "* remotebuildfilename: ${remotebuildfilename}" + fn_print_nl "* remotebuildurl: ${remotebuildurl}" + fn_print_nl "* remotebuildhash: ${remotebuildhash}" + fn_print_nl "* remotebuild: ${remotebuild}" + fi + fi +} + +# The location where the builds are checked and downloaded. +remotelocation="github.com" + +if [ "${firstcommandname}" == "INSTALL" ]; then + fn_update_remotebuild + fn_update_dl +else + # BrainBread requires both Steam app updates and GitHub package updates. + update_steamcmd.sh + + fn_print_dots "Checking for update" + fn_print_dots "Checking for update: ${remotelocation}" + fn_script_log_info "Checking for update: ${remotelocation}" + fn_update_localbuild + fn_update_remotebuild + fn_update_compare +fi From 946cd6fa44c6ac00dd621ee1a846a681189c779b Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sat, 2 May 2026 17:30:15 +0100 Subject: [PATCH 38/53] fix(deps): update .NET runtime version for Vintage Story (#4913) * Changed `dotnet-runtime-8.0` to `dotnet-runtime-10.0` in dependency lists for Ubuntu and Debian. * Enhanced the `check_deps.sh` script to dynamically check for the required .NET runtime version. * Added a warning for users on older distributions regarding potential missing .NET runtimes. --- lgsm/data/debian-12.csv | 2 +- lgsm/data/debian-13.csv | 2 +- lgsm/data/ubuntu-24.04.csv | 2 +- lgsm/data/ubuntu-26.04.csv | 2 +- lgsm/modules/check_deps.sh | 38 ++++++++++++++++++++++++++++++-------- 5 files changed, 34 insertions(+), 12 deletions(-) diff --git a/lgsm/data/debian-12.csv b/lgsm/data/debian-12.csv index 2da22f88c..40e325b6c 100644 --- a/lgsm/data/debian-12.csv +++ b/lgsm/data/debian-12.csv @@ -130,7 +130,7 @@ ut2k4 ut3 ut99 vh,libc6-dev,libatomic1,libpulse-dev -vints,dotnet-runtime-8.0 +vints,dotnet-runtime-10.0 vpmc,openjdk-17-jre vs wet diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index 401cf281c..d53dfb44f 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -130,7 +130,7 @@ ut2k4 ut3 ut99 vh,libc6-dev,libatomic1,libpulse-dev -vints,dotnet-runtime-8.0 +vints,dotnet-runtime-10.0 vpmc,openjdk-25-jre vs wet diff --git a/lgsm/data/ubuntu-24.04.csv b/lgsm/data/ubuntu-24.04.csv index ac683d5d3..0e010abd6 100644 --- a/lgsm/data/ubuntu-24.04.csv +++ b/lgsm/data/ubuntu-24.04.csv @@ -130,7 +130,7 @@ ut2k4 ut3 ut99 vh,libc6-dev,libatomic1,libpulse-dev -vints,dotnet-runtime-8.0 +vints,dotnet-runtime-10.0 vpmc,openjdk-25-jre vs wet diff --git a/lgsm/data/ubuntu-26.04.csv b/lgsm/data/ubuntu-26.04.csv index ac683d5d3..0e010abd6 100644 --- a/lgsm/data/ubuntu-26.04.csv +++ b/lgsm/data/ubuntu-26.04.csv @@ -130,7 +130,7 @@ ut2k4 ut3 ut99 vh,libc6-dev,libatomic1,libpulse-dev -vints,dotnet-runtime-8.0 +vints,dotnet-runtime-10.0 vpmc,openjdk-25-jre vs wet diff --git a/lgsm/modules/check_deps.sh b/lgsm/modules/check_deps.sh index 3d4109e2c..e4bcad4be 100755 --- a/lgsm/modules/check_deps.sh +++ b/lgsm/modules/check_deps.sh @@ -8,15 +8,28 @@ moduleselfname="$(basename "$(readlink -f "${BASH_SOURCE[0]}")")" fn_install_dotnet_repo() { + local dotnetpackage + dotnetpackage="dotnet-runtime-7.0" + + for dep in "${array_deps_missing[@]}"; do + if [[ "${dep}" == dotnet-runtime-* ]]; then + dotnetpackage="${dep}" + break + fi + done + if [ "${distroid}" == "ubuntu" ]; then - # if package dotnet-runtime-7.0 is unavailable in ubuntu repos, add the microsoft repo. - if ! apt-cache show dotnet-runtime-7.0 > /dev/null 2>&1; then + # If the required .NET package is unavailable in Ubuntu repos, add the Microsoft repo. + if ! apt-cache show "${dotnetpackage}" > /dev/null 2>&1; then fn_fetch_file "https://packages.microsoft.com/config/ubuntu/${distroversion}/packages-microsoft-prod.deb" "" "" "" "/tmp" "packages-microsoft-prod.deb" "" "" "" "" sudo dpkg -i /tmp/packages-microsoft-prod.deb fi elif [ "${distroid}" == "debian" ]; then - fn_fetch_file "https://packages.microsoft.com/config/debian/${distroversion}/packages-microsoft-prod.deb" "" "" "" "/tmp" "packages-microsoft-prod.deb" "" "" "" "" - sudo dpkg -i /tmp/packages-microsoft-prod.deb + # If the required .NET package is unavailable in Debian repos, add the Microsoft repo. + if ! apt-cache show "${dotnetpackage}" > /dev/null 2>&1; then + fn_fetch_file "https://packages.microsoft.com/config/debian/${distroversion}/packages-microsoft-prod.deb" "" "" "" "/tmp" "packages-microsoft-prod.deb" "" "" "" "" + sudo dpkg -i /tmp/packages-microsoft-prod.deb + fi fi } @@ -281,10 +294,10 @@ fn_deps_detector() { depstatus=1 monoinstalled=false fi - # .NET Core: A .NET Core repo needs to be installed. - elif [ "${deptocheck}" == "dotnet-runtime-7.0" ]; then - # .NET is not installed. - if dotnet --list-runtimes | grep -q "Microsoft.NETCore.App 7.0"; then + # .NET runtime: check installed runtime version for any dotnet-runtime-X.Y package. + elif [[ "${deptocheck}" =~ ^dotnet-runtime-([0-9]+\.[0-9]+)$ ]]; then + dotnetrequired="${BASH_REMATCH[1]}" + if [ "$(command -v dotnet 2> /dev/null)" ] && dotnet --list-runtimes | grep -q "Microsoft.NETCore.App ${dotnetrequired}"; then depstatus=0 dotnetinstalled=true else @@ -379,6 +392,15 @@ if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" fi fi +# Vintage Story tracks newer .NET runtimes; older distro releases may not ship required packages. +if [ "${shortname}" == "vints" ]; then + if { [ "${distroid}" == "ubuntu" ] && dpkg --compare-versions "${distroversion}" "lt" "24.04"; } || { [ "${distroid}" == "debian" ] && dpkg --compare-versions "${distroversion}" "lt" "12"; } || [ "${distroid}" == "centos" ] || [ "${distroid}" == "rhel" ] || [ "${distroid}" == "rocky" ] || [ "${distroid}" == "almalinux" ]; then + fn_print_warning_nl "${gamename} may require newer .NET runtimes than ${distroname} provides." + echo -e "If startup fails due to missing .NET runtime, upgrading to Ubuntu 24.04+ or Debian 12+ is recommended." + fn_script_log_warn "${gamename} may require newer .NET runtimes than ${distroname} provides." + fi +fi + if [ ! -f "${tmpdir}/dependency-no-check.tmp" ] && [ ! -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then # Check that the distro dependency csv file exists. fn_check_file_github "lgsm/data" "${distroid}-${distroversioncsv}.csv" From 9f278c692fec3de2d7f58258e416dbc9078c9ae0 Mon Sep 17 00:00:00 2001 From: Jacob Gerega <22921310+jgerega107@users.noreply.github.com> Date: Sat, 2 May 2026 13:53:38 -0400 Subject: [PATCH 39/53] feat(newserver): Jabroni Brawl: Episode 3 (#4702) * Added jbep3server * fix(jbep3): add distro deps entries and game icon * fix(jbep3): bootstrap config from server.sample.cfg * chore(prettier): format code --------- Co-authored-by: Daniel Gibbs Co-authored-by: dgibbs64 --- .devcontainer/devcontainer.json | 56 +++++++++---------- .prettierrc.json | 2 +- .vscode/extensions.json | 20 +++---- .../config-lgsm/jbep3server/_default.cfg | 2 +- lgsm/modules/install_config.sh | 3 + 5 files changed, 43 insertions(+), 40 deletions(-) diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json index 506b50754..32c844ac7 100644 --- a/.devcontainer/devcontainer.json +++ b/.devcontainer/devcontainer.json @@ -1,30 +1,30 @@ { - "name": "BASH Dev Container", - "image": "mcr.microsoft.com/devcontainers/base:ubuntu", - "features": { - "ghcr.io/devcontainers-community/npm-features/prettier:1": { - "plugins": "prettier-plugin-sh" - }, - "ghcr.io/devcontainers-extra/features/actionlint:1": {}, - "ghcr.io/devcontainers-extra/features/checkov:1": {}, - "ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {}, - "ghcr.io/devcontainers-extra/features/shellcheck:1": {}, - "ghcr.io/devcontainers-extra/features/yamllint:2": {}, - "ghcr.io/devcontainers/features/github-cli:1": {} - }, - "customizations": { - "vscode": { - "extensions": [ - "DavidAnson.vscode-markdownlint", - "editorconfig.editorconfig", - "esbenp.prettier-vscode", - "github.vscode-github-actions", - "GitHub.vscode-pull-request-github", - "redhat.vscode-yaml", - "timonwong.shellcheck", - "yzhang.markdown-all-in-one" - ] - } - }, - "postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template" + "name": "BASH Dev Container", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers-community/npm-features/prettier:1": { + "plugins": "prettier-plugin-sh" + }, + "ghcr.io/devcontainers-extra/features/actionlint:1": {}, + "ghcr.io/devcontainers-extra/features/checkov:1": {}, + "ghcr.io/devcontainers-extra/features/markdownlint-cli:1": {}, + "ghcr.io/devcontainers-extra/features/shellcheck:1": {}, + "ghcr.io/devcontainers-extra/features/yamllint:2": {}, + "ghcr.io/devcontainers/features/github-cli:1": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "DavidAnson.vscode-markdownlint", + "editorconfig.editorconfig", + "esbenp.prettier-vscode", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "redhat.vscode-yaml", + "timonwong.shellcheck", + "yzhang.markdown-all-in-one" + ] + } + }, + "postCreateCommand": "npm init -y >/dev/null 2>&1 || true && npm install --no-save prettier prettier-plugin-sh prettier-plugin-jinja-template" } diff --git a/.prettierrc.json b/.prettierrc.json index 02d542d50..1902f8021 100644 --- a/.prettierrc.json +++ b/.prettierrc.json @@ -1,3 +1,3 @@ { - "plugins": ["prettier-plugin-sh"] + "plugins": ["prettier-plugin-sh"] } diff --git a/.vscode/extensions.json b/.vscode/extensions.json index d31b65dd2..5c06a83bf 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,12 +1,12 @@ { - "recommendations": [ - "DavidAnson.vscode-markdownlint", - "editorconfig.editorconfig", - "esbenp.prettier-vscode", - "github.vscode-github-actions", - "GitHub.vscode-pull-request-github", - "redhat.vscode-yaml", - "timonwong.shellcheck", - "yzhang.markdown-all-in-one" - ] + "recommendations": [ + "DavidAnson.vscode-markdownlint", + "editorconfig.editorconfig", + "esbenp.prettier-vscode", + "github.vscode-github-actions", + "GitHub.vscode-pull-request-github", + "redhat.vscode-yaml", + "timonwong.shellcheck", + "yzhang.markdown-all-in-one" + ] } diff --git a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg index 2036d3522..069c423db 100644 --- a/lgsm/config-default/config-lgsm/jbep3server/_default.cfg +++ b/lgsm/config-default/config-lgsm/jbep3server/_default.cfg @@ -173,7 +173,7 @@ executabledir="${serverfiles}" executable="./srcds_run.sh" servercfgdir="${systemdir}/cfg" servercfg="${selfname}.cfg" -servercfgdefault="server.cfg" +servercfgdefault="server.sample.cfg" servercfgfullpath="${servercfgdir}/${servercfg}" ## Backup Directory diff --git a/lgsm/modules/install_config.sh b/lgsm/modules/install_config.sh index 08f21c913..e25b8de5c 100755 --- a/lgsm/modules/install_config.sh +++ b/lgsm/modules/install_config.sh @@ -530,6 +530,9 @@ elif [ "${shortname}" == "ios" ]; then fn_default_config_remote fn_set_config_vars fn_list_config_locations +elif [ "${shortname}" == "jbep3" ]; then + fn_default_config_local + fn_list_config_locations elif [ "${shortname}" == "jc2" ]; then array_configs+=(config.lua) fn_default_config_remote From f9905881a945310b8d5425f341b55bfcf7c8030a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:52:46 +0100 Subject: [PATCH 40/53] chore: add AI issue triage workflow and structured-field label rules (#4915) - Add AI triage workflow that flags low-quality issues and requests missing info - Add sync-game-labels script and workflow to maintain game labels from serverlist - Add structured label rules for severity, reproducibility, priority, and scope - Update labeler workflow to support both issues and PRs with dedicated config - Add PR review guidance instructions for maintainers --- .../instructions/pr-review.instructions.md | 29 +++ .github/labeler.yml | 86 ++++++- .github/scripts/sync-game-labels.sh | 87 +++++++ .github/workflows/ai-triage.yml | 229 ++++++++++++++++++ .github/workflows/labeler.yml | 32 ++- .github/workflows/sync-game-labels.yml | 28 +++ 6 files changed, 475 insertions(+), 16 deletions(-) create mode 100644 .github/instructions/pr-review.instructions.md create mode 100644 .github/scripts/sync-game-labels.sh create mode 100644 .github/workflows/ai-triage.yml create mode 100644 .github/workflows/sync-game-labels.yml diff --git a/.github/instructions/pr-review.instructions.md b/.github/instructions/pr-review.instructions.md new file mode 100644 index 000000000..9d0d8fef2 --- /dev/null +++ b/.github/instructions/pr-review.instructions.md @@ -0,0 +1,29 @@ +--- +title: "LinuxGSM PR Review Guidance" +applyTo: "**" +description: "Use when reviewing pull requests in LinuxGSM; prioritize regressions, behavior changes, shell safety, and missing tests over style-only feedback." +--- + +Focus review effort on correctness and operational safety first. + +Primary priorities: + +- Identify behavior regressions and compatibility risks. +- Flag unsafe shell patterns (`rm -rf`, unquoted vars, unchecked command failures). +- Verify workflow changes do not weaken permissions or secret handling. +- Check for missing tests/validation when logic changes. +- Confirm labels, templates, and automation rules stay internally consistent. + +Feedback expectations: + +- Give concrete, actionable findings with file and reason. +- Prefer high-signal issues over style nits. +- If no defects are found, state that clearly and mention residual risk areas. +- Suggest minimal, low-risk fixes before proposing broad refactors. + +LinuxGSM-specific checks: + +- Shell scripts should preserve robust defaults (`set -euo pipefail` where appropriate). +- Label/workflow updates should avoid duplicate or stale taxonomy. +- Automation should fail safe (log and continue for advisory AI; block on true CI errors). +- Keep issue/PR automation rules aligned with templates and existing labels. diff --git a/.github/labeler.yml b/.github/labeler.yml index 34ffd66f1..efca99286 100644 --- a/.github/labeler.yml +++ b/.github/labeler.yml @@ -69,7 +69,7 @@ "game: Ballistic Overkill": - "/(Ballistic Overkill)/i" "game: BATTALION: Legacy": - - "/(BATTALION: Legacy)/i" + - "/(BATTALION: Legacy|Battalion 1944)/i" "game: Barotrauma": - "/(Barotrauma)/i" "game: Counter-Strike: Global Offensive": @@ -77,21 +77,27 @@ "game: Counter-Strike 2": - "/(Counter-Strike 2|CS2)/i" "game: Counter-Strike: Source": - - "/(Counter-Strike: Source|CS:S)/i" + - "/(Counter-Strike: Source|Counter Strike: Source|CS:S)/i" "game: Counter-Strike 1.6": - "/(Counter-Strike 1.6|Counter Strike 1.6|CS 1.6|cs1.6)/i" -"game: Dayz": - - "/(Dayz)/i" +"game: DayZ": + - "/(DayZ|Dayz)/i" +"game: Deathmatch Classic": + - "/(Deathmatch Classic|Death Match Classic|DMC)/i" "game: Don't Starve Together": - "/(Don't Starve Together|Dont Starve Together|DST)/i" "game: Eco": - "/(^Eco$)/i" "game: Factorio": - "/(Factorio)/i" -"game: Garry's Mod": +"game: Garrys Mod": - "/(Garry's Mod|Garrys Mod|GMod)/i" +"game: Hurtworld": + - "/(Hurtworld|Hurtword)/i" +"game: Insurgency": + - "/(^Insurgency$|Insurgecy)/i" "game: Insurgency: Sandstorm": - - "/(Insurgency: Sandstorm|Insurgency)/i" + - "/(Insurgency: Sandstorm)/i" "game: Killing Floor 2": - "/(Killing Floor 2|KF2)/i" "game: Left 4 Dead 2": @@ -100,18 +106,20 @@ - "/(Minecraft)((?!bedrock).)*$/i" "game: Minecraft Bedrock": - "/(Bedrock)/i" -"game: Mumble": - - "/(Mumble)/i" "game: Project Zomboid": - "/(Project Zomboid|PZ)/i" -"game: Quake 3": - - "/(Quake 3|Q3A|q3)/i" +"game: Quake 3: Arena": + - "/(Quake 3: Arena|Quake 3|Q3A|q3)/i" +"game: Quake World": + - "/(Quake World|QuakeWorld)/i" "game: Rising World": - "/(Rising World)/i" "game: Satisfactory": - "/(Satisfactory)/i" "game: Squad": - "/(Squad)/i" +"game: Squad 44": + - "/(Squad 44|Post Scriptum)/i" "game: Starbound": - "/(Starbound)/i" "game: Stationeers": @@ -120,6 +128,8 @@ - "/(Teamspeak 3|ts3)/i" "game: Rust": - "/(Rust)/i" +"game: Soldier Of Fortune 2: Gold Edition": + - "/(Soldier Of Fortune 2: Gold Edition|Soldier of Fortune 2)/i" "game: Unturned": - "/(Unturned)/i" "game: Unreal Tournament 99": @@ -130,6 +140,8 @@ - "/(Unreal Tournament 3|ut3)/i" "game: Valheim": - "/(Valheim)/i" +"game: Zombie Master: Reborn": + - "/(Zombie Master: Reborn|Zombie Master Reborn)/i" # Info "info: alerts": @@ -157,6 +169,54 @@ "type: game server request": - "/(Server Request)/i" "type: bug": - - "/(bug)/i" -"type: feature request": - - "/(feature)/i" + - "/(\\[bug\\]|bug report|type: bug)/i" +"type: bugfix": + - "/(^fix(\\(.+\\))?:|\\[x\\] Bug fix)/im" +"type: feature": + - "/(feature request|new feature|^feat(\\(.+\\))?:|\\[x\\] New feature)/im" +"type: docs": + - "/(^docs(\\(.+\\))?:|documentation|\\[x\\] Comment update)/im" +"type: refactor": + - "/(^refactor(\\(.+\\))?:|\\[x\\] Refactor)/im" +"type: chore": + - "/(^chore(\\(.+\\))?:|^ci(\\(.+\\))?:)/im" + +# Severity (bug reports) +"severity: low": + - "/(severity: low)/i" +"severity: medium": + - "/(severity: medium)/i" +"severity: high": + - "/(severity: high)/i" +"severity: critical": + - "/(severity: critical)/i" + +# Reproducibility (bug reports) +"reproducible: always": + - "/(reproducible: always)/i" +"reproducible: sometimes": + - "/(reproducible: sometimes)/i" +"reproducible: unable": + - "/(reproducible: unable)/i" + +# Regression (bug reports) +"regression: yes": + - "/(regression: yes)/i" + +# Priority (feature requests) +"priority: low": + - "/(priority: low)/i" +"priority: medium": + - "/(priority: medium)/i" +"priority: high": + - "/(priority: high)/i" + +# Scope (feature requests) +"scope: single game": + - "/(scope: single game)/i" +"scope: multiple games": + - "/(scope: multiple games)/i" +"scope: all servers": + - "/(scope: all servers)/i" +"scope: documentation": + - "/(scope: documentation)/i" diff --git a/.github/scripts/sync-game-labels.sh b/.github/scripts/sync-game-labels.sh new file mode 100644 index 000000000..737ec5b74 --- /dev/null +++ b/.github/scripts/sync-game-labels.sh @@ -0,0 +1,87 @@ +#!/usr/bin/env bash +# sync-game-labels.sh +# Reads lgsm/data/serverlist.csv and ensures a "game: " label exists in +# the GitHub repo for every unique game name. Safe to run multiple times. +# +# Requires: gh CLI authenticated with issues:write scope. +# Usage: .github/scripts/sync-game-labels.sh [OWNER/REPO] +# +# The OWNER/REPO argument is optional; if omitted gh uses the current repo. + +set -euo pipefail + +REPO="${1:-}" +SERVERLIST="lgsm/data/serverlist.csv" +LABEL_COLOR="5b21b6" +LABEL_PREFIX="game: " + +normalize_label() { + printf '%s' "$1" | tr '[:upper:]' '[:lower:]' +} + +if [[ ! -f "${SERVERLIST}" ]]; then + echo "ERROR: ${SERVERLIST} not found. Run from the repository root." + exit 1 +fi + +declare -A EXISTING_COLORS=() +declare -A EXISTING_DESCRIPTIONS=() +declare -A EXISTING_NAMES=() + +# Fetch all existing game label metadata once (up to 1000) and cache locally. +echo "Fetching existing labels..." +while IFS=$'\t' read -r NAME COLOR DESCRIPTION; do + [[ -n "${NAME}" ]] || continue + EXISTING_COLORS["${NAME}"]="${COLOR}" + EXISTING_DESCRIPTIONS["${NAME}"]="${DESCRIPTION}" + EXISTING_NAMES["$(normalize_label "${NAME}")"]="${NAME}" +done < <( + gh label list --limit 1000 --json name,color,description ${REPO:+--repo "$REPO"} \ + | jq -r '.[] | select(.name | startswith("game: ")) | [.name, .color, (.description // "")] | @tsv' +) + +# Parse unique game names from the CSV (column 3, skip header). +mapfile -t GAMES < <( + tail -n +2 "${SERVERLIST}" \ + | cut -d',' -f3 \ + | sort -u +) + +CREATED=0 +UPDATED=0 +UNCHANGED=0 + +for GAME in "${GAMES[@]}"; do + LABEL="${LABEL_PREFIX}${GAME}" + DESCRIPTION="Issues related to ${GAME}" + NORMALIZED_LABEL="$(normalize_label "${LABEL}")" + + if [[ -v EXISTING_NAMES["${NORMALIZED_LABEL}"] ]]; then + CURRENT_LABEL="${EXISTING_NAMES["${NORMALIZED_LABEL}"]}" + CURRENT_COLOR="${EXISTING_COLORS["${CURRENT_LABEL}"]}" + CURRENT_DESCRIPTION="${EXISTING_DESCRIPTIONS["${CURRENT_LABEL}"]}" + + if [[ "${CURRENT_LABEL}" != "${LABEL}" || "${CURRENT_COLOR}" != "${LABEL_COLOR}" || "${CURRENT_DESCRIPTION}" != "${DESCRIPTION}" ]]; then + echo " update ${LABEL}" + gh label edit "${CURRENT_LABEL}" \ + --name "${LABEL}" \ + --color "${LABEL_COLOR}" \ + --description "${DESCRIPTION}" \ + ${REPO:+--repo "$REPO"} + (( UPDATED++ )) || true + else + echo " ok ${LABEL}" + (( UNCHANGED++ )) || true + fi + else + echo " create ${LABEL}" + gh label create "${LABEL}" \ + --color "${LABEL_COLOR}" \ + --description "${DESCRIPTION}" \ + ${REPO:+--repo "$REPO"} + (( CREATED++ )) || true + fi +done + +echo "" +echo "Done. Created: ${CREATED} Updated: ${UPDATED} Unchanged: ${UNCHANGED}" diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml new file mode 100644 index 000000000..b48762749 --- /dev/null +++ b/.github/workflows/ai-triage.yml @@ -0,0 +1,229 @@ +name: AI Issue Triage +on: + issues: + types: + - opened + - edited + +permissions: + issues: write + contents: read + +jobs: + ai-triage: + if: github.repository_owner == 'GameServerManagers' + runs-on: ubuntu-latest + steps: + - name: Triage issue with GitHub Models + uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + script: | + const title = context.payload.issue.title || ''; + const body = context.payload.issue.body || ''; + const number = context.payload.issue.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + const AI_MARKER = ''; + + function parseTriageResponse(raw) { + const input = (raw || '').trim(); + if (!input) return {}; + + const candidates = [input]; + const fenced = input.match(/```(?:json)?\s*([\s\S]*?)```/i); + if (fenced?.[1]) candidates.push(fenced[1].trim()); + + const firstBrace = input.indexOf('{'); + const lastBrace = input.lastIndexOf('}'); + if (firstBrace !== -1 && lastBrace > firstBrace) { + candidates.push(input.slice(firstBrace, lastBrace + 1)); + } + + for (const candidate of candidates) { + try { + return JSON.parse(candidate); + } catch (_err) { + // Continue trying fallbacks. + } + } + + return {}; + } + + // For short bodies, apply "needs: more info" label directly. + // Skip the AI call but still label the issue. + const isShortBody = body.trim().length < 80; + if (isShortBody) { + try { + await github.rest.issues.addLabels({ + owner, repo, issue_number: number, + labels: ['needs: more info'], + }); + } catch (err) { + console.log('Could not apply label for short body:', err.message); + } + return; + } + + // โ”€โ”€ Call GitHub Models โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + let triage; + try { + const res = await fetch( + 'https://models.inference.ai.azure.com/chat/completions', + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: 'gpt-4o-mini', + temperature: 0.1, + max_tokens: 400, + messages: [ + { + role: 'system', + content: + 'You are a triage assistant for LinuxGSM, an open-source ' + + 'Linux game server manager. Your role is to:\n' + + '1. Analyze issue quality (completeness, clarity)\n' + + '2. Extract game names mentioned in the issue, even if misspelled or abbreviated\n' + + '3. Suggest corrections for likely typos using fuzzy matching\n' + + '4. Respond ONLY with a valid JSON object โ€” no markdown fences.\n\n' + + 'Common game name variations and typos you should recognize:\n' + + '- "Valhiem" โ†’ "Valheim"\n' + + '- "Rrust" โ†’ "Rust"\n' + + '- "Conterstrike" / "CS" / "CSGO" โ†’ "Counter-Strike: Global Offensive"\n' + + '- "Garrys" / "GMod" โ†’ "Garrys Mod"\n' + + '- "ARK" / "Ark" โ†’ "ARK: Survival Evolved"\n' + + '- "DayZ" / "Dayz" โ†’ "DayZ"\n' + + '- "Insurgency Sandstorm" / "Insurgency 2" โ†’ "Insurgency: Sandstorm"', + }, + { + role: 'user', + content: + `Title: ${title}\n\nBody:\n${body.slice(0, 3000)}\n\n` + + 'Respond with this JSON schema:\n' + + '{\n' + + ' "quality": "good" | "ok" | "poor",\n' + + ' "missing_info": ["list of specific missing fields"],\n' + + ' "detected_game": "canonical game name if one is mentioned, or null",\n' + + ' "game_confidence": "high" | "medium" | "low" | null,\n' + + ' "game_note": "correction suggestion if the user misspelled a game name, or empty string",\n' + + ' "comment": "one or two sentence note to the reporter, or empty string"\n' + + '}', + }, + ], + }), + } + ); + + if (!res.ok) { + console.log(`GitHub Models returned ${res.status} โ€” skipping AI triage.`); + return; + } + + const data = await res.json(); + const raw = data.choices?.[0]?.message?.content || '{}'; + triage = parseTriageResponse(raw); + } catch (err) { + // Never fail the workflow if the AI call errors โ€” it's advisory only. + console.log('AI triage skipped:', err.message); + return; + } + + if (!triage || typeof triage !== 'object') { + triage = {}; + } + + // โ”€โ”€ Act on the result โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + const isPoor = triage.quality === 'poor'; + const missing = Array.isArray(triage.missing_info) ? triage.missing_info : []; + const hasIssues = isPoor || missing.length > 0; + + // Prepare labels to apply + const labelsToApply = []; + + // Check if a game was detected with high confidence + const detectedGame = triage.detected_game; + const gameConfidence = triage.game_confidence; + + if (detectedGame && gameConfidence === 'high') { + labelsToApply.push(`game: ${detectedGame}`); + } + + // Apply "needs: more info" label if quality issues detected + if (hasIssues) { + labelsToApply.push('needs: more info'); + } + + // Apply labels one-by-one so a single failure does not block all labels. + const uniqueLabels = [...new Set(labelsToApply)]; + for (const label of uniqueLabels) { + try { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: number, + labels: [label], + }); + } catch (err) { + console.log(`Could not apply label "${label}":`, err.message); + } + } + + // Post a comment only when there is something specific to say + const gameNote = triage.game_note || ''; + const reporterComment = triage.comment || ''; + + if (!hasIssues && !gameNote) return; + + const missingBlock = missing.length > 0 + ? `\n\n**Missing information:**\n${missing.map(m => `- ${m}`).join('\n')}` + : ''; + + const gameBlock = gameNote + ? `\n\n**Game name note:** ${gameNote}` + : ''; + + const triageCommentBody = + `${AI_MARKER}\n` + + `Thanks for opening this issue! ๐Ÿ‘‹\n\n` + + `${reporterComment}` + + `${missingBlock}` + + `${gameBlock}\n\n` + + `_This note was generated automatically by AI triage and may not be perfect. ` + + `A maintainer will review shortly._`; + + try { + const comments = await github.rest.issues.listComments({ + owner, + repo, + issue_number: number, + per_page: 100, + }); + + const existingAiComment = comments.data.find( + (comment) => comment.user?.type === 'Bot' && comment.body?.includes(AI_MARKER) + ); + + if (existingAiComment) { + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existingAiComment.id, + body: triageCommentBody, + }); + } else { + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: triageCommentBody, + }); + } + } catch (err) { + console.log('Could not post comment:', err.message); + } diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 4a946a861..91b7372a6 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -4,14 +4,24 @@ on: types: - opened - edited + pull_request: + types: + - opened + - edited + - synchronize + - reopened permissions: issues: write + pull-requests: write contents: read +env: + FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: "true" + jobs: issue-labeler: - if: github.repository_owner == 'GameServerManagers' + if: github.repository_owner == 'GameServerManagers' && github.event_name == 'issues' runs-on: ubuntu-latest steps: - name: Issue Labeler @@ -21,12 +31,28 @@ jobs: configuration-path: .github/labeler.yml enable-versioned-regex: 0 include-title: 1 + sync-labels: 1 + + pr-labeler: + if: github.repository_owner == 'GameServerManagers' && github.event_name == 'pull_request' + runs-on: ubuntu-latest + steps: + - name: PR Labeler + uses: github/issue-labeler@v3.4 + with: + repo-token: "${{ secrets.GITHUB_TOKEN }}" + configuration-path: .github/labeler.yml + enable-versioned-regex: 0 + include-title: 1 + include-body: 0 + sync-labels: 1 is-sponsor-label: - if: github.repository_owner == 'GameServerManagers' + if: github.repository_owner == 'GameServerManagers' && github.event_name == 'issues' runs-on: ubuntu-latest steps: - name: Is Sponsor Label - uses: JasonEtco/is-sponsor-label-action@v2 + if: github.event.action == 'opened' + uses: JasonEtco/is-sponsor-label-action@v3 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/sync-game-labels.yml b/.github/workflows/sync-game-labels.yml new file mode 100644 index 000000000..eccb0ed46 --- /dev/null +++ b/.github/workflows/sync-game-labels.yml @@ -0,0 +1,28 @@ +name: Sync Game Labels +on: + push: + branches: + - master + - develop + paths: + - "lgsm/data/serverlist.csv" + workflow_dispatch: {} + +permissions: + issues: write + contents: read + +jobs: + sync-game-labels: + if: github.repository_owner == 'GameServerManagers' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v5 + + - name: Sync game labels from serverlist + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + chmod +x .github/scripts/sync-game-labels.sh + .github/scripts/sync-game-labels.sh From f0ce2737aeb3ad38e647ce5c059a986a3797a2ab Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:53:14 +0100 Subject: [PATCH 41/53] chore: update issue templates, PR template, and CoC (#4914) - bug_report: add expected/actual behavior fields, script name, pre-check checkbox, required steps to reproduce, and AI triage metadata (severity, reproducibility, regression, affects-latest) - feature_request: add priority field, problem statement, scope/impact, alternatives considered; make command optional; remove irrelevant bug-specific triage fields - server_request: add dedicated server checkbox, official docs and Linux binary proof fields; fix CoC placeholder URL; remove irrelevant bug/feature triage fields - config.yml: add private security reporting contact link - pull_request_template: add testing, risk/rollback, breaking changes, and documentation impact sections - CODE_OF_CONDUCT: upgrade from Contributor Covenant v2.1 to v3.0; fill reporting placeholders with GitHub advisory and Discord links --- .github/ISSUE_TEMPLATE/bug_report.yml | 81 ++++++- .github/ISSUE_TEMPLATE/config.yml | 3 + .github/ISSUE_TEMPLATE/feature_request.yml | 42 +++- .github/ISSUE_TEMPLATE/server_request.yml | 38 ++- .github/pull_request_template.md | 28 ++- CODE_OF_CONDUCT.md | 263 ++++++++++++--------- 6 files changed, 327 insertions(+), 128 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e9f2d000b..cbf5f2662 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -8,6 +8,51 @@ body: attributes: value: | Thanks for taking the time to fill out this bug report! + - type: dropdown + id: severity + attributes: + label: Severity + description: Triage metadata used for prioritization. + options: + - "severity: low" + - "severity: medium" + - "severity: high" + - "severity: critical" + validations: + required: true + - type: dropdown + id: reproducibility + attributes: + label: Reproducibility + description: Triage metadata used for prioritization. + options: + - "reproducible: always" + - "reproducible: sometimes" + - "reproducible: unable" + validations: + required: true + - type: dropdown + id: regression + attributes: + label: Regression + description: Triage metadata used for prioritization. + options: + - "regression: yes" + - "regression: no" + - "regression: unknown" + validations: + required: true + - type: dropdown + id: affects-latest + attributes: + label: Affects latest release + description: Triage metadata used for prioritization. + options: + - "latest-release: yes" + - "latest-release: no" + - "latest-release: unknown" + validations: + required: true - type: input id: user-story attributes: @@ -16,6 +61,14 @@ body: placeholder: As a [user description], I want [desired action] so that [desired outcome]. validations: required: true + - type: input + id: script-name + attributes: + label: Script name + description: LinuxGSM script name in use. + placeholder: vhserver + validations: + required: true - type: input id: game attributes: @@ -66,6 +119,22 @@ body: - "command: send" validations: required: true + - type: textarea + id: expected-behavior + attributes: + label: Expected behavior + description: What should happen? + placeholder: Describe the expected result. + validations: + required: true + - type: textarea + id: actual-behavior + attributes: + label: Actual behavior + description: What actually happens? + placeholder: Describe the observed result. + validations: + required: true - type: textarea id: further-info attributes: @@ -74,11 +143,19 @@ body: placeholder: Tell us what you see! validations: required: true + - type: checkboxes + id: prechecks + attributes: + label: Pre-checks + description: Confirm standard troubleshooting has been completed. + options: + - label: I ran update and validate before reporting this issue. + required: true - type: textarea id: logs attributes: label: Relevant log output - description: Please copy and paste any relevant log output. This will be automatically formatted into code, so no need for backticks. + description: Include the exact command used and the full related output (debug/details if available). This will be automatically formatted into code. render: shell - type: textarea id: steps @@ -90,3 +167,5 @@ body: 2. Click on '....' 3. Scroll down to '....' 4. See error + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index d2113c6ca..f9eb19b0c 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -6,3 +6,6 @@ contact_links: - name: Discord Server about: Join the LinuxGSM Discord community server. Discuss your LinuxGSM setup, get help and advice url: https://linuxgsm.com/discord + - name: Report a security vulnerability + about: Please report security vulnerabilities privately, not in public issues. + url: https://github.com/GameServerManagers/LinuxGSM/security/advisories/new diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index f1a8ccaf6..67d7508e1 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -8,6 +8,17 @@ body: attributes: value: | Thanks for taking the time to fill out this feature request! + - type: dropdown + id: priority + attributes: + label: Priority + description: How important is this feature to you? + options: + - "priority: low" + - "priority: medium" + - "priority: high" + validations: + required: true - type: input id: user-story attributes: @@ -64,12 +75,41 @@ body: - "command: update-lgsm" - "command: wipe" - "command: send" + validations: + required: false + - type: textarea + id: problem-statement + attributes: + label: Problem statement + description: What is painful today, and why is this needed? + placeholder: Describe the current limitation or pain point. + validations: + required: true + - type: dropdown + id: scope-impact + attributes: + label: Scope and impact + description: Which area would this change impact? + options: + - "scope: single game" + - "scope: multiple games" + - "scope: all servers" + - "scope: documentation only" + - "scope: ci/cd or automation" + - "scope: other" validations: required: true - type: textarea id: further-info attributes: label: Further information - description: A clear description of what the feature is and any ideas on how to achieve this. + description: A clear description of the proposed solution and any implementation ideas. validations: required: true + - type: textarea + id: alternatives + attributes: + label: Alternatives considered + description: Describe alternatives or workarounds you considered. + validations: + required: false diff --git a/.github/ISSUE_TEMPLATE/server_request.yml b/.github/ISSUE_TEMPLATE/server_request.yml index 31dbc6b81..849bcaa21 100644 --- a/.github/ISSUE_TEMPLATE/server_request.yml +++ b/.github/ISSUE_TEMPLATE/server_request.yml @@ -7,7 +7,7 @@ body: - type: markdown attributes: value: | - Thanks for taking the time to fill out this game server! + Thanks for taking the time to fill out this game server request! - type: input id: game-server attributes: @@ -15,11 +15,19 @@ body: description: What game server would you like to add? validations: required: true + - type: checkboxes + id: dedicated-server + attributes: + label: Dedicated server + description: Confirm this is a dedicated server request and not client hosting. + options: + - label: "Yes, this is a dedicated server (not client hosting)." + required: true - type: checkboxes id: on-linux attributes: label: Linux support - description: Does this game server have Linux support? (not wine) + description: Does this game server have native Linux server support? (not wine) options: - label: "Yes" validations: @@ -38,20 +46,40 @@ body: id: steam-id attributes: label: Steam appid - description: What is the Steam appid of the game server? Use SteamDB to get the appid. (https://steamdb.info). + description: What is the Steam appid of the dedicated server? Required when Steam is Yes. Use SteamDB to get the appid (https://steamdb.info). placeholder: "892970" validations: required: false + - type: textarea + id: official-docs + attributes: + label: Official dedicated server documentation + description: Provide official documentation links for installing/running the dedicated server. + placeholder: | + https://example.com/docs/server-setup + https://example.com/docs/dedicated-server + validations: + required: true + - type: textarea + id: linux-binary-proof + attributes: + label: Linux binary proof + description: Provide evidence that Linux server binaries are available (official docs/download links/version notes). + placeholder: | + https://example.com/downloads/linux-dedicated-server + https://example.com/release-notes/linux-server + validations: + required: true - type: textarea id: guides attributes: label: Guides - description: Links to guides on how to install the game server + description: Links to community or third-party guides on how to install the game server. - type: checkboxes id: terms attributes: label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://example.com) + description: By submitting this issue, you agree to follow our [Code of Conduct](https://github.com/GameServerManagers/LinuxGSM/blob/master/CODE_OF_CONDUCT.md) options: - label: I agree to follow this project's Code of Conduct required: true diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 9f6864e57..d95b4278e 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -12,18 +12,40 @@ Fixes #[issue] - [ ] Refactor (restructures existing code). - [ ] Comment update (typo, spelling, explanation, examples, etc). +## Testing + +Please list the exact validation you performed and the outcome. + +- Commands/tests run: +- Result: +- Environment used (distro/version): + +## Risk and rollback + +- Risk level: low / medium / high +- Rollback plan: + +## Breaking changes + +- [ ] No breaking changes. +- [ ] Breaking changes included (describe below). + +## Documentation impact + +- [ ] No documentation update required. +- [ ] User documentation update required. +- [ ] Developer documentation update required. + ## Checklist PR will not be merged until all steps are complete. - [ ] This pull request links to an issue. -- [ ] This pull request uses the `develop` branch as its base. +- [ ] This pull request uses the develop branch as its base. - [ ] This pull request subject follows the Conventional Commits standard. - [ ] This code follows the style guidelines of this project. - [ ] I have performed a self-review of my code. -- [ ] I have checked that this code is commented where required. - [ ] I have provided a detailed enough description of this PR. -- [ ] I have checked if documentation needs updating. ## Documentation diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index fb935a066..4b118cd09 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -2,131 +2,158 @@ ## Our Pledge -We as members, contributors, and leaders pledge to make participation in our -community a harassment-free experience for everyone, regardless of age, body -size, visible or invisible disability, ethnicity, sex characteristics, gender -identity and expression, level of experience, education, socio-economic status, -nationality, personal appearance, race, caste, color, religion, or sexual identity -and orientation. - -We pledge to act and interact in ways that contribute to an open, welcoming, -diverse, inclusive, and healthy community. - -## Our Standards - -Examples of behavior that contributes to a positive environment for our -community include: - -- Demonstrating empathy and kindness toward other people -- Being respectful of differing opinions, viewpoints, and experiences -- Giving and gracefully accepting constructive feedback -- Accepting responsibility and apologizing to those affected by our mistakes, - and learning from the experience -- Focusing on what is best not just for us as individuals, but for the - overall community - -Examples of unacceptable behavior include: - -- The use of sexualized language or imagery, and sexual attention or - advances of any kind -- Trolling, insulting or derogatory comments, and personal or political attacks -- Public or private harassment -- Publishing others' private information, such as a physical or email - address, without their explicit permission -- Other conduct which could reasonably be considered inappropriate in a - professional setting - -## Enforcement Responsibilities - -Community leaders are responsible for clarifying and enforcing our standards of -acceptable behavior and will take appropriate and fair corrective action in -response to any behavior that they deem inappropriate, threatening, offensive, -or harmful. - -Community leaders have the right and responsibility to remove, edit, or reject -comments, commits, code, wiki edits, issues, and other contributions that are -not aligned to this Code of Conduct, and will communicate reasons for moderation -decisions when appropriate. +We pledge to make our community welcoming, safe, and equitable for all. + +We are committed to fostering an environment that respects and promotes the +dignity, rights, and contributions of all individuals, regardless of characteristics +including race, ethnicity, caste, color, age, physical characteristics, +neurodiversity, disability, sex or gender, gender identity or expression, sexual +orientation, language, philosophy or religion, national or social origin, +socio-economic position, level of education, or other status. The same privileges of +participation are extended to everyone who participates in good faith and in +accordance with this Covenant. + +## Encouraged Behaviors + +While acknowledging differences in social norms, we all strive to meet our +community's expectations for positive behavior. We also understand that our words +and actions may be interpreted differently than we intend based on culture, +background, or native language. + +With these considerations in mind, we agree to behave mindfully toward each other +and act in ways that center our shared values, including: + +1. Respecting the **purpose of our community**, our activities, and our ways of gathering. +2. Engaging **kindly and honestly** with others. +3. Respecting **different viewpoints** and experiences. +4. **Taking responsibility** for our actions and contributions. +5. Gracefully giving and accepting **constructive feedback**. +6. Committing to **repairing harm** when it occurs. +7. Behaving in other ways that promote and sustain the **well-being of our community**. + +## Restricted Behaviors + +We agree to restrict the following behaviors in our community. Instances, +threats, and promotion of these behaviors are violations of this Code of Conduct. + +1. **Harassment.** Violating explicitly expressed boundaries or engaging in + unnecessary personal attention after any clear request to stop. +2. **Character attacks.** Making insulting, demeaning, or pejorative comments + directed at a community member or group of people. +3. **Stereotyping or discrimination.** Characterizing anyone's personality or + behavior on the basis of immutable identities or traits. +4. **Sexualization.** Behaving in a way that would generally be considered + inappropriately intimate in the context or purpose of the community. +5. **Violating confidentiality.** Sharing or acting on someone's personal or + private information without their permission. +6. **Endangerment.** Causing, encouraging, or threatening violence or other harm + toward any person or group. +7. Behaving in other ways that **threaten the well-being** of our community. + +### Other Restrictions + +1. **Misleading identity.** Impersonating someone else for any reason, or + pretending to be someone else to evade enforcement actions. +2. **Failing to credit sources.** Not properly crediting the sources of content + you contribute. +3. **Promotional materials.** Sharing marketing or other commercial content in a + way that is outside the norms of the community. +4. **Irresponsible communication.** Failing to responsibly present content which + includes, links or describes any other restricted behaviors. + +## Reporting an Issue + +Tensions can occur between community members even when they are trying their best +to collaborate. Not every conflict represents a code of conduct violation, and this +Code of Conduct reinforces encouraged behaviors and norms that can help avoid +conflicts and minimize harm. + +When an incident does occur, it is important to report it promptly. To report a +possible violation, please use one of the following methods: + +- **GitHub (private):** [Submit a private security advisory](https://github.com/GameServerManagers/LinuxGSM/security/advisories/new) +- **Discord:** Contact a moderator via the [LinuxGSM Discord server](https://linuxgsm.com/discord) + +Community Moderators take reports of violations seriously and will make every +effort to respond in a timely manner. They will investigate all reports of code of +conduct violations, reviewing messages, logs, and recordings, or interviewing +witnesses and other participants. Community Moderators will keep investigation and +enforcement actions as transparent as possible while prioritizing safety and +confidentiality. In order to honor these values, enforcement actions are carried out +in private with the involved parties, but communicating to the whole community may +be part of a mutually agreed upon resolution. + +## Addressing and Repairing Harm + +If an investigation by the Community Moderators finds that this Code of Conduct +has been violated, the following enforcement ladder may be used to determine how +best to repair harm, based on the incident's impact on the individuals involved +and the community as a whole. Depending on the severity of a violation, lower +rungs on the ladder may be skipped. + +1. **Warning** + 1. Event: A violation involving a single incident or series of incidents. + 2. Consequence: A private, written warning from the Community Moderators. + 3. Repair: Examples of repair include a private written apology, acknowledgement + of responsibility, and seeking clarification on expectations. + +2. **Temporarily Limited Activities** + 1. Event: A repeated incidence of a violation that previously resulted in a + warning, or the first incidence of a more serious violation. + 2. Consequence: A private, written warning with a time-limited cooldown period + designed to underscore the seriousness of the situation and give the community + members involved time to process the incident. The cooldown period may be + limited to particular communication channels or interactions with particular + community members. + 3. Repair: Examples of repair may include making an apology, using the cooldown + period to reflect on actions and impact, and being thoughtful about + re-entering community spaces after the period is over. + +3. **Temporary Suspension** + 1. Event: A pattern of repeated violation which the Community Moderators have + tried to address with warnings, or a single serious violation. + 2. Consequence: A private written warning with conditions for return from + suspension. In general, temporary suspensions give the person being suspended + time to reflect upon their behavior and possible corrective actions. + 3. Repair: Examples of repair include respecting the spirit of the suspension, + meeting the specified conditions for return, and being thoughtful about how to + reintegrate with the community when the suspension is lifted. + +4. **Permanent Ban** + 1. Event: A pattern of repeated code of conduct violations that other steps on + the ladder have failed to resolve, or a violation so serious that the Community + Moderators determine there is no way to keep the community safe with this + person as a member. + 2. Consequence: Access to all community spaces, tools, and communication channels + is removed. In general, permanent bans should be rarely used, should have + strong reasoning behind them, and should only be resorted to if working through + other remedies has failed to change the behavior. + 3. Repair: There is no possible repair in cases of this severity. + +This enforcement ladder is intended as a guideline. It does not limit the ability +of Community Moderators to use their discretion and judgment, in keeping with the +best interests of our community. ## Scope -This Code of Conduct applies within all community spaces, and also applies when -an individual is officially representing the community in public spaces. -Examples of representing our community include using an official e-mail address, +This Code of Conduct applies within all community spaces, and also applies when an +individual is officially representing the community in public or other spaces. +Examples of representing our community include using an official email address, posting via an official social media account, or acting as an appointed representative at an online or offline event. -## Enforcement - -Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported to the community leaders responsible for enforcement at -[INSERT CONTACT METHOD]. -All complaints will be reviewed and investigated promptly and fairly. - -All community leaders are obligated to respect the privacy and security of the -reporter of any incident. - -## Enforcement Guidelines - -Community leaders will follow these Community Impact Guidelines in determining -the consequences for any action they deem in violation of this Code of Conduct: - -### 1. Correction - -**Community Impact**: Use of inappropriate language or other behavior deemed -unprofessional or unwelcome in the community. - -**Consequence**: A private, written warning from community leaders, providing -clarity around the nature of the violation and an explanation of why the -behavior was inappropriate. A public apology may be requested. - -### 2. Warning - -**Community Impact**: A violation through a single incident or series -of actions. - -**Consequence**: A warning with consequences for continued behavior. No -interaction with the people involved, including unsolicited interaction with -those enforcing the Code of Conduct, for a specified period of time. This -includes avoiding interactions in community spaces as well as external channels -like social media. Violating these terms may lead to a temporary or -permanent ban. - -### 3. Temporary Ban - -**Community Impact**: A serious violation of community standards, including -sustained inappropriate behavior. - -**Consequence**: A temporary ban from any sort of interaction or public -communication with the community for a specified period of time. No public or -private interaction with the people involved, including unsolicited interaction -with those enforcing the Code of Conduct, is allowed during this period. -Violating these terms may lead to a permanent ban. - -### 4. Permanent Ban - -**Community Impact**: Demonstrating a pattern of violation of community -standards, including sustained inappropriate behavior, harassment of an -individual, or aggression toward or disparagement of classes of individuals. - -**Consequence**: A permanent ban from any sort of public interaction within -the community. - ## Attribution -This Code of Conduct is adapted from the [Contributor Covenant][homepage], -version 2.1, available at -[https://www.contributor-covenant.org/version/2/1/code_of_conduct.html][v2.1]. - -Community Impact Guidelines were inspired by -[Mozilla's code of conduct enforcement ladder][mozilla coc]. +This Code of Conduct is adapted from the Contributor Covenant, version 3.0, +permanently available at . -For answers to common questions about this code of conduct, see the FAQ at -[https://www.contributor-covenant.org/faq][faq]. Translations are available -at [https://www.contributor-covenant.org/translations][translations]. +Contributor Covenant is stewarded by the Organization for Ethical Source and +licensed under CC BY-SA 4.0. To view a copy of this license, visit +. -[homepage]: https://www.contributor-covenant.org -[v2.1]: https://www.contributor-covenant.org/version/2/1/code_of_conduct.html -[mozilla coc]: https://github.com/mozilla/diversity -[faq]: https://www.contributor-covenant.org/faq -[translations]: https://www.contributor-covenant.org/translations +For answers to common questions about Contributor Covenant, see the FAQ at +. Translations are provided at +. Additional enforcement and +community guideline resources can be found at +. The enforcement ladder was +inspired by the work of [Mozilla's code of conduct team](https://github.com/mozilla/inclusion). From 46fa6954441c2ecc3e791969b4c0c8b226eb534c Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:00:24 +0000 Subject: [PATCH 42/53] fix: use is-sponsor-label-action v2 (v3 does not exist) The v3 release does not exist for JasonEtco/is-sponsor-label-action. Use v2 which is the latest stable release. The Node.js 24 compatibility is handled by the FORCE_JAVASCRIPT_ACTIONS_TO_NODE24 environment variable. --- .github/workflows/labeler.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/labeler.yml b/.github/workflows/labeler.yml index 91b7372a6..f1e47bc50 100644 --- a/.github/workflows/labeler.yml +++ b/.github/workflows/labeler.yml @@ -53,6 +53,6 @@ jobs: steps: - name: Is Sponsor Label if: github.event.action == 'opened' - uses: JasonEtco/is-sponsor-label-action@v3 + uses: JasonEtco/is-sponsor-label-action@v2 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} From a183369e5568e7febc13fa10b609f8a3933e5b10 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:05:00 +0000 Subject: [PATCH 43/53] fix: remove AI triage workflow The GitHub Models API requires specialized authentication that is not available through secrets.GITHUB_TOKEN. The workflow consistently fails with 401 Unauthorized. The rule-based label automation (labeler.yml) continues to function correctly and provides automated labeling based on structured template fields. --- .github/workflows/ai-triage.yml | 229 -------------------------------- 1 file changed, 229 deletions(-) delete mode 100644 .github/workflows/ai-triage.yml diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml deleted file mode 100644 index b48762749..000000000 --- a/.github/workflows/ai-triage.yml +++ /dev/null @@ -1,229 +0,0 @@ -name: AI Issue Triage -on: - issues: - types: - - opened - - edited - -permissions: - issues: write - contents: read - -jobs: - ai-triage: - if: github.repository_owner == 'GameServerManagers' - runs-on: ubuntu-latest - steps: - - name: Triage issue with GitHub Models - uses: actions/github-script@v7 - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - with: - script: | - const title = context.payload.issue.title || ''; - const body = context.payload.issue.body || ''; - const number = context.payload.issue.number; - const owner = context.repo.owner; - const repo = context.repo.repo; - const AI_MARKER = ''; - - function parseTriageResponse(raw) { - const input = (raw || '').trim(); - if (!input) return {}; - - const candidates = [input]; - const fenced = input.match(/```(?:json)?\s*([\s\S]*?)```/i); - if (fenced?.[1]) candidates.push(fenced[1].trim()); - - const firstBrace = input.indexOf('{'); - const lastBrace = input.lastIndexOf('}'); - if (firstBrace !== -1 && lastBrace > firstBrace) { - candidates.push(input.slice(firstBrace, lastBrace + 1)); - } - - for (const candidate of candidates) { - try { - return JSON.parse(candidate); - } catch (_err) { - // Continue trying fallbacks. - } - } - - return {}; - } - - // For short bodies, apply "needs: more info" label directly. - // Skip the AI call but still label the issue. - const isShortBody = body.trim().length < 80; - if (isShortBody) { - try { - await github.rest.issues.addLabels({ - owner, repo, issue_number: number, - labels: ['needs: more info'], - }); - } catch (err) { - console.log('Could not apply label for short body:', err.message); - } - return; - } - - // โ”€โ”€ Call GitHub Models โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - let triage; - try { - const res = await fetch( - 'https://models.inference.ai.azure.com/chat/completions', - { - method: 'POST', - headers: { - 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`, - 'Content-Type': 'application/json', - }, - body: JSON.stringify({ - model: 'gpt-4o-mini', - temperature: 0.1, - max_tokens: 400, - messages: [ - { - role: 'system', - content: - 'You are a triage assistant for LinuxGSM, an open-source ' + - 'Linux game server manager. Your role is to:\n' + - '1. Analyze issue quality (completeness, clarity)\n' + - '2. Extract game names mentioned in the issue, even if misspelled or abbreviated\n' + - '3. Suggest corrections for likely typos using fuzzy matching\n' + - '4. Respond ONLY with a valid JSON object โ€” no markdown fences.\n\n' + - 'Common game name variations and typos you should recognize:\n' + - '- "Valhiem" โ†’ "Valheim"\n' + - '- "Rrust" โ†’ "Rust"\n' + - '- "Conterstrike" / "CS" / "CSGO" โ†’ "Counter-Strike: Global Offensive"\n' + - '- "Garrys" / "GMod" โ†’ "Garrys Mod"\n' + - '- "ARK" / "Ark" โ†’ "ARK: Survival Evolved"\n' + - '- "DayZ" / "Dayz" โ†’ "DayZ"\n' + - '- "Insurgency Sandstorm" / "Insurgency 2" โ†’ "Insurgency: Sandstorm"', - }, - { - role: 'user', - content: - `Title: ${title}\n\nBody:\n${body.slice(0, 3000)}\n\n` + - 'Respond with this JSON schema:\n' + - '{\n' + - ' "quality": "good" | "ok" | "poor",\n' + - ' "missing_info": ["list of specific missing fields"],\n' + - ' "detected_game": "canonical game name if one is mentioned, or null",\n' + - ' "game_confidence": "high" | "medium" | "low" | null,\n' + - ' "game_note": "correction suggestion if the user misspelled a game name, or empty string",\n' + - ' "comment": "one or two sentence note to the reporter, or empty string"\n' + - '}', - }, - ], - }), - } - ); - - if (!res.ok) { - console.log(`GitHub Models returned ${res.status} โ€” skipping AI triage.`); - return; - } - - const data = await res.json(); - const raw = data.choices?.[0]?.message?.content || '{}'; - triage = parseTriageResponse(raw); - } catch (err) { - // Never fail the workflow if the AI call errors โ€” it's advisory only. - console.log('AI triage skipped:', err.message); - return; - } - - if (!triage || typeof triage !== 'object') { - triage = {}; - } - - // โ”€โ”€ Act on the result โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ - const isPoor = triage.quality === 'poor'; - const missing = Array.isArray(triage.missing_info) ? triage.missing_info : []; - const hasIssues = isPoor || missing.length > 0; - - // Prepare labels to apply - const labelsToApply = []; - - // Check if a game was detected with high confidence - const detectedGame = triage.detected_game; - const gameConfidence = triage.game_confidence; - - if (detectedGame && gameConfidence === 'high') { - labelsToApply.push(`game: ${detectedGame}`); - } - - // Apply "needs: more info" label if quality issues detected - if (hasIssues) { - labelsToApply.push('needs: more info'); - } - - // Apply labels one-by-one so a single failure does not block all labels. - const uniqueLabels = [...new Set(labelsToApply)]; - for (const label of uniqueLabels) { - try { - await github.rest.issues.addLabels({ - owner, - repo, - issue_number: number, - labels: [label], - }); - } catch (err) { - console.log(`Could not apply label "${label}":`, err.message); - } - } - - // Post a comment only when there is something specific to say - const gameNote = triage.game_note || ''; - const reporterComment = triage.comment || ''; - - if (!hasIssues && !gameNote) return; - - const missingBlock = missing.length > 0 - ? `\n\n**Missing information:**\n${missing.map(m => `- ${m}`).join('\n')}` - : ''; - - const gameBlock = gameNote - ? `\n\n**Game name note:** ${gameNote}` - : ''; - - const triageCommentBody = - `${AI_MARKER}\n` + - `Thanks for opening this issue! ๐Ÿ‘‹\n\n` + - `${reporterComment}` + - `${missingBlock}` + - `${gameBlock}\n\n` + - `_This note was generated automatically by AI triage and may not be perfect. ` + - `A maintainer will review shortly._`; - - try { - const comments = await github.rest.issues.listComments({ - owner, - repo, - issue_number: number, - per_page: 100, - }); - - const existingAiComment = comments.data.find( - (comment) => comment.user?.type === 'Bot' && comment.body?.includes(AI_MARKER) - ); - - if (existingAiComment) { - await github.rest.issues.updateComment({ - owner, - repo, - comment_id: existingAiComment.id, - body: triageCommentBody, - }); - } else { - await github.rest.issues.createComment({ - owner, - repo, - issue_number: number, - body: triageCommentBody, - }); - } - } catch (err) { - console.log('Could not post comment:', err.message); - } From 418f46f8779e0d37e2073778955df64814718ecf Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:05:05 +0000 Subject: [PATCH 44/53] Revert "fix: remove AI triage workflow" This reverts commit a183369e5568e7febc13fa10b609f8a3933e5b10. --- .github/workflows/ai-triage.yml | 229 ++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 .github/workflows/ai-triage.yml diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml new file mode 100644 index 000000000..b48762749 --- /dev/null +++ b/.github/workflows/ai-triage.yml @@ -0,0 +1,229 @@ +name: AI Issue Triage +on: + issues: + types: + - opened + - edited + +permissions: + issues: write + contents: read + +jobs: + ai-triage: + if: github.repository_owner == 'GameServerManagers' + runs-on: ubuntu-latest + steps: + - name: Triage issue with GitHub Models + uses: actions/github-script@v7 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + with: + script: | + const title = context.payload.issue.title || ''; + const body = context.payload.issue.body || ''; + const number = context.payload.issue.number; + const owner = context.repo.owner; + const repo = context.repo.repo; + const AI_MARKER = ''; + + function parseTriageResponse(raw) { + const input = (raw || '').trim(); + if (!input) return {}; + + const candidates = [input]; + const fenced = input.match(/```(?:json)?\s*([\s\S]*?)```/i); + if (fenced?.[1]) candidates.push(fenced[1].trim()); + + const firstBrace = input.indexOf('{'); + const lastBrace = input.lastIndexOf('}'); + if (firstBrace !== -1 && lastBrace > firstBrace) { + candidates.push(input.slice(firstBrace, lastBrace + 1)); + } + + for (const candidate of candidates) { + try { + return JSON.parse(candidate); + } catch (_err) { + // Continue trying fallbacks. + } + } + + return {}; + } + + // For short bodies, apply "needs: more info" label directly. + // Skip the AI call but still label the issue. + const isShortBody = body.trim().length < 80; + if (isShortBody) { + try { + await github.rest.issues.addLabels({ + owner, repo, issue_number: number, + labels: ['needs: more info'], + }); + } catch (err) { + console.log('Could not apply label for short body:', err.message); + } + return; + } + + // โ”€โ”€ Call GitHub Models โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + let triage; + try { + const res = await fetch( + 'https://models.inference.ai.azure.com/chat/completions', + { + method: 'POST', + headers: { + 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`, + 'Content-Type': 'application/json', + }, + body: JSON.stringify({ + model: 'gpt-4o-mini', + temperature: 0.1, + max_tokens: 400, + messages: [ + { + role: 'system', + content: + 'You are a triage assistant for LinuxGSM, an open-source ' + + 'Linux game server manager. Your role is to:\n' + + '1. Analyze issue quality (completeness, clarity)\n' + + '2. Extract game names mentioned in the issue, even if misspelled or abbreviated\n' + + '3. Suggest corrections for likely typos using fuzzy matching\n' + + '4. Respond ONLY with a valid JSON object โ€” no markdown fences.\n\n' + + 'Common game name variations and typos you should recognize:\n' + + '- "Valhiem" โ†’ "Valheim"\n' + + '- "Rrust" โ†’ "Rust"\n' + + '- "Conterstrike" / "CS" / "CSGO" โ†’ "Counter-Strike: Global Offensive"\n' + + '- "Garrys" / "GMod" โ†’ "Garrys Mod"\n' + + '- "ARK" / "Ark" โ†’ "ARK: Survival Evolved"\n' + + '- "DayZ" / "Dayz" โ†’ "DayZ"\n' + + '- "Insurgency Sandstorm" / "Insurgency 2" โ†’ "Insurgency: Sandstorm"', + }, + { + role: 'user', + content: + `Title: ${title}\n\nBody:\n${body.slice(0, 3000)}\n\n` + + 'Respond with this JSON schema:\n' + + '{\n' + + ' "quality": "good" | "ok" | "poor",\n' + + ' "missing_info": ["list of specific missing fields"],\n' + + ' "detected_game": "canonical game name if one is mentioned, or null",\n' + + ' "game_confidence": "high" | "medium" | "low" | null,\n' + + ' "game_note": "correction suggestion if the user misspelled a game name, or empty string",\n' + + ' "comment": "one or two sentence note to the reporter, or empty string"\n' + + '}', + }, + ], + }), + } + ); + + if (!res.ok) { + console.log(`GitHub Models returned ${res.status} โ€” skipping AI triage.`); + return; + } + + const data = await res.json(); + const raw = data.choices?.[0]?.message?.content || '{}'; + triage = parseTriageResponse(raw); + } catch (err) { + // Never fail the workflow if the AI call errors โ€” it's advisory only. + console.log('AI triage skipped:', err.message); + return; + } + + if (!triage || typeof triage !== 'object') { + triage = {}; + } + + // โ”€โ”€ Act on the result โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + const isPoor = triage.quality === 'poor'; + const missing = Array.isArray(triage.missing_info) ? triage.missing_info : []; + const hasIssues = isPoor || missing.length > 0; + + // Prepare labels to apply + const labelsToApply = []; + + // Check if a game was detected with high confidence + const detectedGame = triage.detected_game; + const gameConfidence = triage.game_confidence; + + if (detectedGame && gameConfidence === 'high') { + labelsToApply.push(`game: ${detectedGame}`); + } + + // Apply "needs: more info" label if quality issues detected + if (hasIssues) { + labelsToApply.push('needs: more info'); + } + + // Apply labels one-by-one so a single failure does not block all labels. + const uniqueLabels = [...new Set(labelsToApply)]; + for (const label of uniqueLabels) { + try { + await github.rest.issues.addLabels({ + owner, + repo, + issue_number: number, + labels: [label], + }); + } catch (err) { + console.log(`Could not apply label "${label}":`, err.message); + } + } + + // Post a comment only when there is something specific to say + const gameNote = triage.game_note || ''; + const reporterComment = triage.comment || ''; + + if (!hasIssues && !gameNote) return; + + const missingBlock = missing.length > 0 + ? `\n\n**Missing information:**\n${missing.map(m => `- ${m}`).join('\n')}` + : ''; + + const gameBlock = gameNote + ? `\n\n**Game name note:** ${gameNote}` + : ''; + + const triageCommentBody = + `${AI_MARKER}\n` + + `Thanks for opening this issue! ๐Ÿ‘‹\n\n` + + `${reporterComment}` + + `${missingBlock}` + + `${gameBlock}\n\n` + + `_This note was generated automatically by AI triage and may not be perfect. ` + + `A maintainer will review shortly._`; + + try { + const comments = await github.rest.issues.listComments({ + owner, + repo, + issue_number: number, + per_page: 100, + }); + + const existingAiComment = comments.data.find( + (comment) => comment.user?.type === 'Bot' && comment.body?.includes(AI_MARKER) + ); + + if (existingAiComment) { + await github.rest.issues.updateComment({ + owner, + repo, + comment_id: existingAiComment.id, + body: triageCommentBody, + }); + } else { + await github.rest.issues.createComment({ + owner, + repo, + issue_number: number, + body: triageCommentBody, + }); + } + } catch (err) { + console.log('Could not post comment:', err.message); + } From f9b722b45564b9721a728e5fb5d6d022186cff9a Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:05:35 +0000 Subject: [PATCH 45/53] docs: clarify GitHub Models availability in AI triage workflow Add comments explaining that GitHub Models access may not be available in all environments and that 401 (Unauthorized) errors are expected and handled gracefully. The workflow will skip AI triage silently but continue processing the issue through other automation. --- .github/workflows/ai-triage.yml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml index b48762749..59e109601 100644 --- a/.github/workflows/ai-triage.yml +++ b/.github/workflows/ai-triage.yml @@ -5,6 +5,11 @@ on: - opened - edited +# Note: This workflow uses GitHub Models which may not be available +# in all environments. If GitHub Models API returns 401 or is unavailable, +# the workflow will skip gracefully and the issue will still be processed +# by other automation (labeler, etc.) + permissions: issues: write contents: read @@ -68,6 +73,10 @@ jobs: } // โ”€โ”€ Call GitHub Models โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€ + // Note: GitHub Models access may not be available in all environments. + // If the API returns 401 (Unauthorized), it means GitHub Models is not + // enabled for this repository or the current token lacks access. + // The workflow will gracefully skip AI triage and continue. let triage; try { const res = await fetch( @@ -120,6 +129,8 @@ jobs: } ); + // GitHub Models may return 401 if not available for this repository. + // This is expected and not an error โ€” the workflow simply skips AI triage. if (!res.ok) { console.log(`GitHub Models returned ${res.status} โ€” skipping AI triage.`); return; From 095b8ddf36e0107ee41cc4d73d1f165f07dab961 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:10:08 +0000 Subject: [PATCH 46/53] fix(ai-triage): grant models permission to GITHUB_TOKEN --- .github/workflows/ai-triage.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml index 59e109601..145571cf4 100644 --- a/.github/workflows/ai-triage.yml +++ b/.github/workflows/ai-triage.yml @@ -13,6 +13,7 @@ on: permissions: issues: write contents: read + models: read jobs: ai-triage: From 479211f22fe2b8c04ff87b2bcd5c7a2641525e47 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:17:18 +0000 Subject: [PATCH 47/53] fix(ai-triage): use GitHub Models REST inference endpoint --- .github/workflows/ai-triage.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ai-triage.yml b/.github/workflows/ai-triage.yml index 145571cf4..fba1e4cf1 100644 --- a/.github/workflows/ai-triage.yml +++ b/.github/workflows/ai-triage.yml @@ -81,15 +81,17 @@ jobs: let triage; try { const res = await fetch( - 'https://models.inference.ai.azure.com/chat/completions', + `https://models.github.ai/orgs/${owner}/inference/chat/completions`, { method: 'POST', headers: { + 'Accept': 'application/vnd.github+json', 'Authorization': `Bearer ${process.env.GITHUB_TOKEN}`, + 'X-GitHub-Api-Version': '2026-03-10', 'Content-Type': 'application/json', }, body: JSON.stringify({ - model: 'gpt-4o-mini', + model: 'openai/gpt-4.1-mini', temperature: 0.1, max_tokens: 400, messages: [ From a6af3c9773e10dd3d17ce84d463f210f171d09c8 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:21:11 +0000 Subject: [PATCH 48/53] chore(actions): tidy workflows and script layout --- .../details-check-generate-matrix.sh | 0 .../serverlist-validate-game-icons.sh | 0 .../serverlist-validate.sh | 16 ---------- .../{workflows => scripts}/version-check.sh | 0 ...update-copyright-years-in-license-file.yml | 29 ------------------- .github/workflows/details-check.yml | 2 +- .github/workflows/serverlist-validate.yml | 4 +-- .github/workflows/version-check.yml | 2 +- 8 files changed, 4 insertions(+), 49 deletions(-) rename .github/{workflows => scripts}/details-check-generate-matrix.sh (100%) rename .github/{workflows => scripts}/serverlist-validate-game-icons.sh (100%) rename .github/{workflows => scripts}/serverlist-validate.sh (60%) rename .github/{workflows => scripts}/version-check.sh (100%) delete mode 100644 .github/workflows/action-update-copyright-years-in-license-file.yml diff --git a/.github/workflows/details-check-generate-matrix.sh b/.github/scripts/details-check-generate-matrix.sh similarity index 100% rename from .github/workflows/details-check-generate-matrix.sh rename to .github/scripts/details-check-generate-matrix.sh diff --git a/.github/workflows/serverlist-validate-game-icons.sh b/.github/scripts/serverlist-validate-game-icons.sh similarity index 100% rename from .github/workflows/serverlist-validate-game-icons.sh rename to .github/scripts/serverlist-validate-game-icons.sh diff --git a/.github/workflows/serverlist-validate.sh b/.github/scripts/serverlist-validate.sh similarity index 60% rename from .github/workflows/serverlist-validate.sh rename to .github/scripts/serverlist-validate.sh index 3d83d89da..9f3826cfa 100755 --- a/.github/workflows/serverlist-validate.sh +++ b/.github/scripts/serverlist-validate.sh @@ -22,20 +22,4 @@ for csv in "${csvlist[@]}"; do fi done -# Compare all game servers listed in serverlist.csv to $shortname-icon.png files in ${datadir}/gameicons -# if the game server is listed in serverlist.csv then it will have a $shortname-icon.png file - -# loop though shortname in serverlist.csv -echo "" -echo "Checking that all the game servers listed in serverlist.csv have a shortname-icon.png file" -for shortname in $(tail -n +2 serverlist.csv | cut -d ',' -f1); do - # check if $shortname-icon.png exists - if [ ! -f "gameicons/${shortname}-icon.png" ]; then - echo "ERROR: gameicons/${shortname}-icon.png does not exist" - exitcode=1 - else - echo "OK: gameicons/${shortname}-icon.png exists" - fi -done - exit "${exitcode}" diff --git a/.github/workflows/version-check.sh b/.github/scripts/version-check.sh similarity index 100% rename from .github/workflows/version-check.sh rename to .github/scripts/version-check.sh diff --git a/.github/workflows/action-update-copyright-years-in-license-file.yml b/.github/workflows/action-update-copyright-years-in-license-file.yml deleted file mode 100644 index ab1549f0e..000000000 --- a/.github/workflows/action-update-copyright-years-in-license-file.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Update copyright year(s) in license file - -on: - workflow_dispatch: - schedule: - - cron: "0 3 1 1 *" # 03:00 AM on January 1 - -permissions: - contents: write - -jobs: - update-license-year: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - fetch-depth: 0 - persist-credentials: false - - name: Action Update License Year - uses: FantasticFiasco/action-update-license-year@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - path: LICENSE.md - - name: Merge pull request - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr merge --merge --delete-branch diff --git a/.github/workflows/details-check.yml b/.github/workflows/details-check.yml index 856ab2d2a..2c3d858d6 100644 --- a/.github/workflows/details-check.yml +++ b/.github/workflows/details-check.yml @@ -26,7 +26,7 @@ jobs: uses: actions/checkout@v6 - name: Generate matrix with generate-matrix.sh - run: chmod +x .github/workflows/details-check-generate-matrix.sh; .github/workflows/details-check-generate-matrix.sh + run: .github/scripts/details-check-generate-matrix.sh - name: Set Matrix id: set-matrix diff --git a/.github/workflows/serverlist-validate.yml b/.github/workflows/serverlist-validate.yml index e2016eddf..3e8807407 100644 --- a/.github/workflows/serverlist-validate.yml +++ b/.github/workflows/serverlist-validate.yml @@ -18,7 +18,7 @@ jobs: uses: actions/checkout@v6 - name: Compare Versions - run: chmod +x .github/workflows/serverlist-validate.sh; .github/workflows/serverlist-validate.sh + run: .github/scripts/serverlist-validate.sh - name: Validate Game Icons - run: chmod +x .github/workflows/serverlist-validate-game-icons.sh; .github/workflows/serverlist-validate-game-icons.sh + run: .github/scripts/serverlist-validate-game-icons.sh diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index 2b4448643..0726295a4 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -14,4 +14,4 @@ jobs: uses: actions/checkout@v6 - name: Version Check - run: chmod +x .github/workflows/version-check.sh; .github/workflows/version-check.sh + run: .github/scripts/version-check.sh From 05f46e18d5d451ec1d59bfe4becc5d02bb168bee Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 01:21:11 +0000 Subject: [PATCH 49/53] chore(actions): tidy workflows and script layout --- .../details-check-generate-matrix.sh | 0 .../serverlist-validate-game-icons.sh | 0 .../serverlist-validate.sh | 16 ---------- .../{workflows => scripts}/version-check.sh | 0 ...update-copyright-years-in-license-file.yml | 29 ------------------- .github/workflows/details-check.yml | 2 +- .github/workflows/serverlist-validate.yml | 4 +-- .github/workflows/version-check.yml | 2 +- 8 files changed, 4 insertions(+), 49 deletions(-) rename .github/{workflows => scripts}/details-check-generate-matrix.sh (100%) rename .github/{workflows => scripts}/serverlist-validate-game-icons.sh (100%) rename .github/{workflows => scripts}/serverlist-validate.sh (60%) rename .github/{workflows => scripts}/version-check.sh (100%) delete mode 100644 .github/workflows/action-update-copyright-years-in-license-file.yml diff --git a/.github/workflows/details-check-generate-matrix.sh b/.github/scripts/details-check-generate-matrix.sh similarity index 100% rename from .github/workflows/details-check-generate-matrix.sh rename to .github/scripts/details-check-generate-matrix.sh diff --git a/.github/workflows/serverlist-validate-game-icons.sh b/.github/scripts/serverlist-validate-game-icons.sh similarity index 100% rename from .github/workflows/serverlist-validate-game-icons.sh rename to .github/scripts/serverlist-validate-game-icons.sh diff --git a/.github/workflows/serverlist-validate.sh b/.github/scripts/serverlist-validate.sh similarity index 60% rename from .github/workflows/serverlist-validate.sh rename to .github/scripts/serverlist-validate.sh index 3d83d89da..9f3826cfa 100755 --- a/.github/workflows/serverlist-validate.sh +++ b/.github/scripts/serverlist-validate.sh @@ -22,20 +22,4 @@ for csv in "${csvlist[@]}"; do fi done -# Compare all game servers listed in serverlist.csv to $shortname-icon.png files in ${datadir}/gameicons -# if the game server is listed in serverlist.csv then it will have a $shortname-icon.png file - -# loop though shortname in serverlist.csv -echo "" -echo "Checking that all the game servers listed in serverlist.csv have a shortname-icon.png file" -for shortname in $(tail -n +2 serverlist.csv | cut -d ',' -f1); do - # check if $shortname-icon.png exists - if [ ! -f "gameicons/${shortname}-icon.png" ]; then - echo "ERROR: gameicons/${shortname}-icon.png does not exist" - exitcode=1 - else - echo "OK: gameicons/${shortname}-icon.png exists" - fi -done - exit "${exitcode}" diff --git a/.github/workflows/version-check.sh b/.github/scripts/version-check.sh similarity index 100% rename from .github/workflows/version-check.sh rename to .github/scripts/version-check.sh diff --git a/.github/workflows/action-update-copyright-years-in-license-file.yml b/.github/workflows/action-update-copyright-years-in-license-file.yml deleted file mode 100644 index ab1549f0e..000000000 --- a/.github/workflows/action-update-copyright-years-in-license-file.yml +++ /dev/null @@ -1,29 +0,0 @@ -name: Update copyright year(s) in license file - -on: - workflow_dispatch: - schedule: - - cron: "0 3 1 1 *" # 03:00 AM on January 1 - -permissions: - contents: write - -jobs: - update-license-year: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@v6 - with: - fetch-depth: 0 - persist-credentials: false - - name: Action Update License Year - uses: FantasticFiasco/action-update-license-year@v3 - with: - token: ${{ secrets.GITHUB_TOKEN }} - path: LICENSE.md - - name: Merge pull request - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - gh pr merge --merge --delete-branch diff --git a/.github/workflows/details-check.yml b/.github/workflows/details-check.yml index c58aa0ae4..ccccbbdaa 100644 --- a/.github/workflows/details-check.yml +++ b/.github/workflows/details-check.yml @@ -24,7 +24,7 @@ jobs: uses: actions/checkout@v4 - name: Generate matrix with generate-matrix.sh - run: chmod +x .github/workflows/details-check-generate-matrix.sh; .github/workflows/details-check-generate-matrix.sh + run: .github/scripts/details-check-generate-matrix.sh - name: Set Matrix id: set-matrix diff --git a/.github/workflows/serverlist-validate.yml b/.github/workflows/serverlist-validate.yml index c2605b062..4fb830702 100644 --- a/.github/workflows/serverlist-validate.yml +++ b/.github/workflows/serverlist-validate.yml @@ -15,7 +15,7 @@ jobs: uses: actions/checkout@v4 - name: Compare Versions - run: chmod +x .github/workflows/serverlist-validate.sh; .github/workflows/serverlist-validate.sh + run: .github/scripts/serverlist-validate.sh - name: Validate Game Icons - run: chmod +x .github/workflows/serverlist-validate-game-icons.sh; .github/workflows/serverlist-validate-game-icons.sh + run: .github/scripts/serverlist-validate-game-icons.sh diff --git a/.github/workflows/version-check.yml b/.github/workflows/version-check.yml index cfa7615bd..d3c4a5276 100644 --- a/.github/workflows/version-check.yml +++ b/.github/workflows/version-check.yml @@ -14,4 +14,4 @@ jobs: uses: actions/checkout@v4 - name: Version Check - run: chmod +x .github/workflows/version-check.sh; .github/workflows/version-check.sh + run: .github/scripts/version-check.sh From 907a463f0679f9a48bcc6545c02c282cb5c116a9 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 02:37:43 +0100 Subject: [PATCH 50/53] fix: Update Debian 13 dependencies and add to issue templates (#4916) - Replace libncursesw5 with libncursesw6 (removed from Debian 13) - Replace libxml2-utils with libxml2 (removed from Debian 13) - Add Debian 13 to bug report and feature request distro options Fixes #4847: libncursesw5 and libxml2-utils do not exist on Debian 13 --- .github/ISSUE_TEMPLATE/bug_report.yml | 7 +++++++ .github/ISSUE_TEMPLATE/feature_request.yml | 7 +++++++ lgsm/data/debian-13.csv | 8 ++++---- 3 files changed, 18 insertions(+), 4 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml index e9f2d000b..41797fdff 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.yml +++ b/.github/ISSUE_TEMPLATE/bug_report.yml @@ -30,11 +30,18 @@ body: label: Linux distro multiple: true options: + - Ubuntu 26.04 - Ubuntu 24.04 - Ubuntu 22.04 - Ubuntu 20.04 + - Debian 13 - Debian 12 - Debian 11 + - AlmaLinux 9 + - AlmaLinux 8 + - Rocky 10 + - Rocky 9 + - Rocky 8 - RedHat 9 - RedHat 8 - Other diff --git a/.github/ISSUE_TEMPLATE/feature_request.yml b/.github/ISSUE_TEMPLATE/feature_request.yml index f1a8ccaf6..e71032485 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.yml +++ b/.github/ISSUE_TEMPLATE/feature_request.yml @@ -30,11 +30,18 @@ body: label: Linux distro multiple: true options: + - Ubuntu 26.04 - Ubuntu 24.04 - Ubuntu 22.04 - Ubuntu 20.04 + - Debian 13 - Debian 12 - Debian 11 + - AlmaLinux 9 + - AlmaLinux 8 + - Rocky 10 + - Rocky 9 + - Rocky 8 - RedHat 9 - RedHat 8 - Other diff --git a/lgsm/data/debian-13.csv b/lgsm/data/debian-13.csv index d53dfb44f..94c6cf1ae 100644 --- a/lgsm/data/debian-13.csv +++ b/lgsm/data/debian-13.csv @@ -16,7 +16,7 @@ bfv,libncurses5:i386,libstdc++5:i386 bmdm,libncurses5:i386 bo bs -bt,libicu-dev,dos2unix,libxml2-utils +bt,libicu-dev,dos2unix,libxml2 btl cc ck,xvfb,libxi6 @@ -71,7 +71,7 @@ mcb mcv mh mohaa,libstdc++5:i386 -mta,libncursesw5,libxml2-utils +mta,libncursesw6,libxml2 nd nec nmrih @@ -104,14 +104,14 @@ sb sbots scpsl,mono-complete,libicu76 scpslsm,mono-complete -sdtd,telnet,expect,libxml2-utils +sdtd,telnet,expect,libxml2 sf sfc sm,telnet,expect sof2 sol squad -st,libxml2-utils +st,libxml2 stn sven,libssl3:i386,zlib1g:i386 terraria From 2c4da53248fcf4cd089d1dae3ebe11a965ee2bb8 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Sun, 3 May 2026 02:48:13 +0100 Subject: [PATCH 51/53] fix: Correct CSV file path in update-lgsm command (#4917) The distro CSV file was being fetched with an absolute path instead of a repository-relative path, causing malformed URLs like /master//home/user/lgsm/data/debian-12.csv Changed fn_fetch_file_github first parameter from "${datadir}" to "lgsm/data" to match the correct repository path structure. Fixes #4856: ERROR: Downloading debian-12.csv on update-lgsm --- lgsm/modules/command_update_linuxgsm.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lgsm/modules/command_update_linuxgsm.sh b/lgsm/modules/command_update_linuxgsm.sh index 3fd4cc681..80ff74cfb 100755 --- a/lgsm/modules/command_update_linuxgsm.sh +++ b/lgsm/modules/command_update_linuxgsm.sh @@ -188,7 +188,7 @@ if [ -f "${datadir}/${distroid}-${distroversioncsv}.csv" ]; then fn_print_update_eol_nl fn_script_log "Checking ${remotereponame} ${distroid}-${distroversioncsv}.csv" rm -f "${datadir:?}/${distroid}-${distroversioncsv}.csv" - fn_fetch_file_github "${datadir}" "${distroid}-${distroversioncsv}.csv" "${datadir}" "nochmodx" "norun" "noforce" "nohash" + fn_fetch_file_github "lgsm/data" "${distroid}-${distroversioncsv}.csv" "${datadir}" "nochmodx" "norun" "noforce" "nohash" else fn_print_skip_eol_nl fn_script_log_pass "Checking ${remotereponame} ${distroid}-${distroversioncsv}.csv" From 3a56a6cef35e15e8883a9d14d62308d82b295657 Mon Sep 17 00:00:00 2001 From: Daniel Gibbs Date: Mon, 4 May 2026 11:03:30 +0100 Subject: [PATCH 52/53] chore(actions): Optimize details-check workflow for PRs Enhances the `details-check` workflow to run more efficiently on pull requests. This commit introduces logic to: - Trigger the workflow on pull requests to the `develop` branch. - Analyze changed files to determine the scope of the checks required: - Run a full matrix if core `details`-related scripts are modified. - Run a targeted matrix only for servers whose `config-lgsm` files are changed. - Skip the check entirely if no relevant files are touched. - Provide a concise summary of the `details`, `parse-game-details`, and `query-raw` outcomes directly in the GitHub Actions job summary. This optimization significantly reduces CI/CD run times and resource consumption for pull requests by avoiding unnecessary checks across all game servers, improving developer efficiency. --- .../scripts/details-check-generate-matrix.sh | 6 ++ .github/workflows/details-check.yml | 86 +++++++++++++++++-- 2 files changed, 87 insertions(+), 5 deletions(-) diff --git a/.github/scripts/details-check-generate-matrix.sh b/.github/scripts/details-check-generate-matrix.sh index 1093a46cf..eff7d5416 100755 --- a/.github/scripts/details-check-generate-matrix.sh +++ b/.github/scripts/details-check-generate-matrix.sh @@ -8,6 +8,12 @@ echo -n "\"include\":[" >> "shortnamearray.json" while read -r line; do shortname=$(echo "$line" | awk -F, '{ print $1 }') + # If TARGETED_SHORTNAMES is set, skip servers not in the list + if [ -n "${TARGETED_SHORTNAMES:-}" ]; then + if ! echo "${TARGETED_SHORTNAMES}" | grep -qw "${shortname}"; then + continue + fi + fi export shortname servername=$(echo "$line" | awk -F, '{ print $2 }') export servername diff --git a/.github/workflows/details-check.yml b/.github/workflows/details-check.yml index 2c3d858d6..d4f7f644f 100644 --- a/.github/workflows/details-check.yml +++ b/.github/workflows/details-check.yml @@ -5,6 +5,9 @@ on: push: branches: - develop + pull_request: + branches: + - develop permissions: contents: read @@ -25,15 +28,56 @@ jobs: - name: Checkout uses: actions/checkout@v6 + - name: Detect targeted servers (PR only) + id: targeted + if: github.event_name == 'pull_request' + run: | + changed=$(git diff --name-only origin/${{ github.base_ref }}...HEAD) + echo "Changed files:" + echo "$changed" + + # Only these modules directly affect what 'details', 'parse-game-details' + # and 'query-raw' output. Everything else (install, fix, update, check_*, + # data CSVs, game icons, etc.) is irrelevant to this check. + details_core='^(linuxgsm\.sh|lgsm/modules/(info_game|info_messages|command_details|command_dev_parse_game_details|command_dev_query_raw|core_modules)\.sh)$' + if echo "$changed" | grep -qE "${details_core}"; then + echo "Details-relevant core file changed โ€” using full matrix." + echo "mode=full" >> "$GITHUB_OUTPUT" + else + # Extract shortnames from changed config-lgsm paths + shortnames=$(echo "$changed" \ + | grep -oE 'lgsm/config-default/config-lgsm/[a-z0-9]+server' \ + | sed 's|lgsm/config-default/config-lgsm/||;s|server$||' \ + | sort -u) + if [ -z "$shortnames" ]; then + echo "No server configs or core files changed โ€” skipping matrix." + echo "mode=skip" >> "$GITHUB_OUTPUT" + else + echo "Targeted servers: $shortnames" + echo "mode=targeted" >> "$GITHUB_OUTPUT" + printf '%s\n' $shortnames > targeted_shortnames.txt + fi + fi + - name: Generate matrix with generate-matrix.sh - run: .github/scripts/details-check-generate-matrix.sh + if: github.event_name != 'pull_request' || steps.targeted.outputs.mode != 'skip' + run: | + if [ -f targeted_shortnames.txt ]; then + TARGETED_SHORTNAMES=$(cat targeted_shortnames.txt) .github/scripts/details-check-generate-matrix.sh + else + .github/scripts/details-check-generate-matrix.sh + fi - name: Set Matrix id: set-matrix run: | - shortnamearray=$(cat shortnamearray.json) - echo "${shortnamearray}" - echo -n "matrix=${shortnamearray}" >> "$GITHUB_OUTPUT" + if [ ! -f shortnamearray.json ]; then + echo 'matrix={"include":[]}' >> "$GITHUB_OUTPUT" + else + shortnamearray=$(cat shortnamearray.json) + echo "${shortnamearray}" + echo -n "matrix=${shortnamearray}" >> "$GITHUB_OUTPUT" + fi details-check: if: github.repository_owner == 'GameServerManagers' @@ -50,8 +94,14 @@ jobs: - name: Download linuxgsm.sh run: wget "https://raw.githubusercontent.com/GameServerManagers/LinuxGSM/${LGSM_REF}/linuxgsm.sh"; chmod +x linuxgsm.sh + - name: Cache apt packages + uses: actions/cache@v4 + with: + path: /var/cache/apt/archives + key: apt-${{ runner.os }}-libxml2-utils-jq + - name: Install dependencies - run: sudo apt-get install libxml2-utils jq + run: sudo apt-get install -y --no-install-recommends libxml2-utils jq - name: Create serverfiles directory run: mkdir -p serverfiles @@ -91,10 +141,36 @@ jobs: run: grep "startparameters" lgsm/config-default/config-lgsm/${{ matrix.shortname }}server/_default.cfg - name: Details + id: details run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server details - name: Detect details + id: detect-details run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server parse-game-details - name: Query Raw + id: query-raw run: LGSM_GITHUBBRANCH="${LGSM_REF}" ./${{ matrix.shortname }}server query-raw + + - name: Write job summary + if: always() + run: | + status_icon() { + case "$1" in + success) echo "โœ…" ;; + failure) echo "โŒ" ;; + skipped) echo "โญ๏ธ" ;; + *) echo "โš ๏ธ" ;; + esac + } + details_icon=$(status_icon "${{ steps.details.outcome }}") + parse_icon=$(status_icon "${{ steps.detect-details.outcome }}") + query_icon=$(status_icon "${{ steps.query-raw.outcome }}") + { + echo "## ${{ matrix.shortname }}server" + echo "| Step | Result |" + echo "|------|--------|" + echo "| Details | ${details_icon} ${{ steps.details.outcome }} |" + echo "| Parse game details | ${parse_icon} ${{ steps.detect-details.outcome }} |" + echo "| Query raw | ${query_icon} ${{ steps.query-raw.outcome }} |" + } >> "$GITHUB_STEP_SUMMARY" From df0cc0469a8b5eaa928d6092fe7a49f740692a17 Mon Sep 17 00:00:00 2001 From: Nikolay Asenov <10465782+nasenov@users.noreply.github.com> Date: Sun, 19 Jul 2026 16:10:45 +0300 Subject: [PATCH 53/53] fix(mods_list): update AMX Mod X version to latest release (#4932) --- lgsm/modules/mods_list.sh | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/lgsm/modules/mods_list.sh b/lgsm/modules/mods_list.sh index b3f9877f1..0870e1db1 100755 --- a/lgsm/modules/mods_list.sh +++ b/lgsm/modules/mods_list.sh @@ -19,40 +19,40 @@ metamodlatestfile="metamod-${metamodversion}.zip" metamoddownloadurl="https://www.amxmodx.org/release/${metamodlatestfile}" metamodurl="${metamoddownloadurl}" # AMX Mod X: Base -amxxbaseversion="1.8.2" +amxxbaseversion="1.9.0-git5303" amxxbasemod="base" amxxbaselatestfile="amxmodx-${amxxbaseversion}-${amxxbasemod}-linux.tar.gz" -amxxbasedownloadurl="https://www.amxmodx.org/release/${amxxbaselatestfile}" +amxxbasedownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxbaselatestfile}" amxxbaseurl="${amxxbasedownloadurl}" # AMX Mod X: Counter-Strike -amxxcsversion="1.8.2" +amxxcsversion="1.9.0-git5303" amxxcsmod="cstrike" amxxcslatestfile="amxmodx-${amxxbaseversion}-${amxxcsmod}-linux.tar.gz" -amxxcsdownloadurl="https://www.amxmodx.org/release/${amxxcslatestfile}" +amxxcsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxcslatestfile}" amxxcsurl="${amxxcsdownloadurl}" # AMX Mod X: Day of Defeat -amxxdodversion="1.8.2" +amxxdodversion="1.9.0-git5303" amxxdodmod="dod" amxxdodlatestfile="amxmodx-${amxxdodversion}-${amxxdodmod}-linux.tar.gz" -amxxdoddownloadurl="https://www.amxmodx.org/release/${amxxdodlatestfile}" +amxxdoddownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxdodlatestfile}" amxxdodurl="${amxxdoddownloadurl}" # AMX Mod X: Team Fortress Classic -amxxtfcversion="1.8.2" +amxxtfcversion="1.9.0-git5303" amxxtfcmod="tfc" amxxtfclatestfile="amxmodx-${amxxtfcversion}-${amxxtfcmod}-linux.tar.gz" -amxxtfcdownloadurl="https://www.amxmodx.org/release/${amxxtfclatestfile}" +amxxtfcdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxtfclatestfile}" amxxtfcurl="${amxxtfcdownloadurl}" # AMX Mod X: Natural Selection -amxxnsversion="1.8.2" +amxxnsversion="1.9.0-git5303" amxxnsmod="ns" amxxnslatestfile="amxmodx-${amxxnsversion}-${amxxnsmod}-linux.tar.gz" -amxxnsdownloadurl="https://www.amxmodx.org/release/${amxxnslatestfile}" +amxxnsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxnslatestfile}" amxxnsurl="${amxxnsdownloadurl}" # AMX Mod X: The Specialists -amxxtsversion="1.8.2" +amxxtsversion="1.9.0-git5303" amxxtsmod="ts" amxxtslatestfile="amxmodx-${amxxtsversion}-${amxxtsmod}-linux.tar.gz" -amxxtsdownloadurl="https://www.amxmodx.org/release/${amxxtslatestfile}" +amxxtsdownloadurl="https://github.com/alliedmodders/amxmodx/releases/download/1.9.0.5303/${amxxtslatestfile}" amxxtsurl="${amxxtsdownloadurl}" # Metamod:Source metamodsourceversion="1.12"