Skip to content

Wars sharedclasspath#617

Draft
jonenst wants to merge 7 commits into
mainfrom
wars_sharedclasspath
Draft

Wars sharedclasspath#617
jonenst wants to merge 7 commits into
mainfrom
wars_sharedclasspath

Conversation

@jonenst
Copy link
Copy Markdown
Contributor

@jonenst jonenst commented May 11, 2026

PR Summary

horrible POC of 2.5g ram running loadflows and security-analysis on country size neworks

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented May 11, 2026

Review Change Stack

📝 Walkthrough

Walkthrough

This PR introduces a complete multiwar deployment system that packages 21+ GridSuite microservices as WARs on a single Tomcat container. It includes a build automation script that generates lightweight wrapper projects, manages shared dependencies, applies selective auto-configuration exclusions, Docker Compose orchestration, and comprehensive documentation of classloading challenges and solutions.

Changes

Multiwar Deployment Architecture

Layer / File(s) Summary
Environment & Compose Structure
docker-compose/multiwar/.env, docker-compose/multiwar/docker-compose.yml
Environment variables enable geo-data/lines-catalog initialization, set project name to gridstudy, and configure Tomcat port to 12345. Docker Compose entry point includes both technical and multiwar-specific configurations.
Approach & Technical Documentation
docker-compose/multiwar/README.md, docker-compose/multiwar/SHARED_CLASSLOADING_ISSUES.txt
README explains the wrapper-project approach without modifying server sources, provides quick-start commands, and lists prerequisites and excluded servers. Technical documentation details 9+ classloading issues (bean collisions, unintended auto-configurations, type-identity conflicts, resource bundle problems) with specific fixes, plus memory savings estimates and build-time resolution strategies.
Tomcat Server Configuration
docker-compose/multiwar/server.xml
Custom Tomcat server.xml configures shutdown port 8005 and HTTP port 8080, enables core listeners and an in-memory user database, and sets startStopThreads="1" to enforce sequential WAR deployment with WAR unpacking and auto-deploy enabled.
Service Configuration & Routing
docker-compose/multiwar/itools-config.yml, docker-compose/multiwar/nonwars-to-tomcat-config/common-application.yml
iTools configuration merges settings from multiple sources, specifies component homes, selects NetworkStore, limits concurrency to 4 cores, and defines load-flow/security-analysis parameters. Common application configuration routes powsybl and gridsuite service base-URIs to the single Tomcat container at http://tomcat:8080/, except config-server routed to its dedicated container.
WAR Build Pipeline Setup & Helpers
docker-compose/multiwar/wars.sh (lines 1–138)
Bash script framework establishes strict execution mode, directory structure (gen/externalized-war-configs/, gen/war-wrappers/, gen/shared-lib/, gen/wars/), Docker base URL, argument parsing for --only and --help, logging/error helpers, server manifest list with filtering, build selection logic, and base-URI resolution utilities.
WAR Build Pipeline Phases
docker-compose/multiwar/wars.sh (lines 143–811)
Five-phase pipeline: (1) generate_local_config_override() parses server application-local files to detect service references and emit base-uri overrides; (2) add_shared_lib_autoconfig_exclusions() inspects dependency lists to identify unused Spring features and prepend auto-config exclusions; (3) find_common_deps() generates servers-reactor, runs single mvn dependency:list, selects highest-version winning deps, and generates shared-deps POM; (4) generate_wrappers() creates per-server wrapper WAR projects with SpringBootServletInitializer initializers and packagingIncludes to exclude shared deps; (5) build_wars() compiles all WARs in one Maven invocation, (6) collect_shared_libs() downloads shared JARs and packages reports*.properties into resource-bundles.jar, and (7) deploy_to_compose_dirs() copies WAR artifacts into final deployment structure. Main execution chains these phases in order.
Docker Service Orchestration
docker-compose/multiwar/docker-compose.multiwar.yml
Tomcat service mounts custom server.xml, WAR artifacts, shared libraries, and externalized configs; sets CATALINA_OPTS for default profile and bean-override allowance; entrypoint installs shared JARs to Tomcat lib/ and blocks on Elasticsearch health. Non-WAR services (config-server, notification servers, gateway) expose fixed ports with mounted config files and JVM memory limits. Frontend apps (gridstudy/gridexplore/gridadmin) mount IDP and environment settings. Mock OIDC server and apps-metadata Apache service complete the stack with appropriate ports and resource constraints.
🚥 Pre-merge checks | ✅ 2 | ❌ 3

❌ Failed checks (1 warning, 2 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 72.73% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title 'Wars sharedclasspath' is cryptic and uses technical jargon without clearly explaining the main change; it lacks clarity about what was added or modified. Revise the title to be more descriptive, such as 'Add Docker Compose multiwar deployment with shared classpath support' to clearly convey the primary change.
Description check ❓ Inconclusive The description mentions running loadflows and security-analysis on country-size networks but does not meaningfully describe the changeset, which primarily adds Docker Compose configuration, scripts, and documentation for multiwar deployment. Expand the description to explain that this PR introduces Docker Compose multiwar setup including WAR deployment scripts, shared classpath configuration, and supporting documentation.
✅ Passed checks (2 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

Tip

💬 Introducing Slack Agent: The best way for teams to turn conversations into code.

Slack Agent is built on CodeRabbit's deep understanding of your code, so your team can collaborate across the entire SDLC without losing context.

  • Generate code and open pull requests
  • Plan features and break down work
  • Investigate incidents and troubleshoot customer tickets together
  • Automate recurring tasks and respond to alerts with triggers
  • Summarize progress and report instantly

Built for teams:

  • Shared memory across your entire org—no repeating context
  • Per-thread sandboxes to safely plan and execute work
  • Governance built-in—scoped access, auditability, and budget controls

One agent for your entire SDLC. Right inside Slack.

👉 Get started


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 7

🧹 Nitpick comments (8)
docker-compose/multiwar/docker-compose.multiwar.yml (2)

53-152: ⚖️ Poor tradeoff

Heavy duplication across non-WAR services.

config-server, config-notification-server, study-notification-server, directory-notification-server, and gateway share identical JAVA_TOOL_OPTIONS, command, sysctls, memswap_limit, and deploy.resources.limits blocks. The inline comment at line 55-57 already notes this should reuse definitions from docker-compose.base.yml. A YAML anchor (&svc-defaults / <<: *svc-defaults) would also work locally if base reuse is out of scope for the POC.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/docker-compose.multiwar.yml` around lines 53 - 152,
Extract the repeated common service configuration (JAVA_TOOL_OPTIONS, command,
sysctls, memswap_limit, deploy.resources.limits) into a YAML anchor (e.g.
&svc-defaults) placed near the top of the services block, then reference it in
each service (config-server, config-notification-server,
study-notification-server, directory-notification-server, gateway) using the
merge key (<<: *svc-defaults); ensure the anchor contains the exact keys to be
shared and keep service-specific keys like image, ports, volumes and any extra
mounts outside the merged block so each service still overrides or extends as
needed.

6-10: 💤 Low value

Pin the Tomcat image by digest for reproducibility.

tomcat:10.1-jdk21 is a floating tag — the underlying image will shift over time, which can silently change JDK build, OS packages, or default config and break the carefully-tuned classloading setup. apps-metadata-server at line 246 already pins by digest; same treatment here would make this POC reproducible.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/docker-compose.multiwar.yml` around lines 6 - 10, The
tomcat service currently uses a floating tag "image: tomcat:10.1-jdk21" which
must be pinned by digest for reproducibility; locate the tomcat service block
(the "tomcat" service and the "image: tomcat:10.1-jdk21" line) and replace the
tag with the corresponding digest-pinned reference (e.g.,
"tomcat@sha256:<digest>") obtained from the Docker registry (docker pull or
manifest inspect) so the docker-compose.multiwar.yml uses an immutable image
reference.
docker-compose/multiwar/wars.sh (3)

496-509: 💤 Low value

Dead variables flagged by shellcheck.

  • Line 496: t (the type field) is read but never used in the loop body — rename to _ for clarity.
  • Line 530: SHARED_DEPS_FILE is assigned and never read anywhere else in the script.
  • Line 783 (${propfile#$res_dir/}): the pattern variable is unquoted, so glob metachars in $res_dir (unlikely but possible) would be interpreted; quote it.
🔧 Proposed cleanups
-    while IFS=: read -r g a t classifier v; do
+    while IFS=: read -r g a _ classifier v; do
-    # Export for use by generate_wrappers
-    SHARED_DEPS_FILE="$deps_dir/_shared.txt"
     DEPS_DIR="$deps_dir"
-                local rel="${propfile#$res_dir/}"
+                local rel="${propfile#"$res_dir"/}"

Also applies to: 530-531

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/wars.sh` around lines 496 - 509, The loop reading
dependencies uses an unused variable `t` and should be renamed to `_` in the
while-read that constructs `shared_deps_xml` (look for the while IFS=: read -r g
a t classifier v; do ... done < "$deps_dir/_shared.txt") to silence shellcheck;
remove or stop assigning the unused `SHARED_DEPS_FILE` variable (search for its
assignment around the 530 area) since it’s never used; and quote the parameter
expansion `${propfile#$res_dir/}` (used later where propfile is stripped of
$res_dir) to prevent accidental globbing by changing to a quoted form so the
pattern is treated literally.

451-453: 💤 Low value

grep -P (PCRE) is not portable.

Lines 451 uses grep -oP, which depends on PCRE-enabled grep. BSD/macOS grep does not support -P by default and fails with "invalid option". If this script is only ever run on a Linux build host that's fine, otherwise prefer awk or sed.

-        grep -oP '^\s+\S+' "$deps_file" | sed 's/^[[:space:]]*//' | \
+        awk 'NF && /^[[:space:]]+\S+/ {sub(/^[[:space:]]*/, ""); print $1}' "$deps_file" | \
             awk -F: 'NF==5 {print $1":"$2":"$3"::"$4} NF>=6 {print $1":"$2":"$3":"$4":"$5}' | \
             sort -u > "$deps_dir/${ctx}.parsed"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/wars.sh` around lines 451 - 453, The use of grep -oP
is not portable; replace the grep+sed step with a POSIX-compatible awk that
extracts the first non-space token from each line of "$deps_file" before piping
to the existing awk/ sort sequence. For example, change the pipeline that starts
with grep -oP '^\s+\S+' "$deps_file" to use awk '{ if
(match($0,/^[[:space:]]*[^[:space:]]+/)) print substr($0,RSTART,RLENGTH) }'
"$deps_file" | awk -F: 'NF==5 {print $1":"$2":"$3"::"$4} NF>=6 {print
$1":"$2":"$3":"$4":"$5}' | sort -u > "$deps_dir/${ctx}.parsed", keeping the same
variables deps_file, deps_dir and ctx so the rest of wars.sh remains unchanged.

285-370: 💤 Low value

Implicit dependency on DEPS_DIR set by find_common_deps.

add_shared_lib_autoconfig_exclusions reads ${DEPS_DIR}/${ctx}.parsed (line 289) but DEPS_DIR is only assigned at the end of find_common_deps (line 531) and never declared at module scope. With set -u, calling these functions out of order — or in isolation while debugging — will fail with an "unbound variable" error far from the cause. Consider initializing DEPS_DIR next to the other path globals at the top of the script.

 SHARED_LIB_DIR="$SCRIPT_DIR/gen/shared-lib"
+DEPS_DIR="$SCRIPT_DIR/gen/deps"

…and then drop the assignment at line 531.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/wars.sh` around lines 285 - 370, The function
add_shared_lib_autoconfig_exclusions relies on DEPS_DIR but DEPS_DIR is only set
inside find_common_deps, causing unbound-variable failures when functions are
invoked out of order; to fix, declare and initialize DEPS_DIR alongside the
other top-level path globals at the top of the script (so DEPS_DIR exists even
before find_common_deps runs) and then remove the later assignment to DEPS_DIR
from find_common_deps; update references to DEPS_DIR in
add_shared_lib_autoconfig_exclusions and find_common_deps as needed to ensure
the single authoritative initialization is at the module scope.
docker-compose/multiwar/README.md (3)

3-3: ⚡ Quick win

Remove AI generation attribution from user-facing documentation.

This attribution is unprofessional in production documentation. Users care about accuracy and utility, not the generation method. If attribution is necessary, place it in commit messages or internal comments instead.

📝 Proposed fix
 # WAR Deploy Tool
 
-Generated with little supervision by opus4.6.
-
 Builds GridSuite microservices as WAR files for docker-compose deployment, **without modifying any original source files**.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/README.md` at line 3, Remove the user-facing AI
generation attribution line "Generated with little supervision by opus4.6." from
the README content so the documentation no longer references the generation
method; if you need to retain provenance, add that note to the commit message or
an internal comment in the repo instead.

1-59: ⚡ Quick win

Document architectural trade-offs and limitations.

This multiwar approach eliminates the isolation benefits of microservices architecture. Consider adding a "Limitations & Trade-offs" section that covers:

  • Shared classloader risks (dependency conflicts, security boundaries)
  • Single point of failure (one Tomcat crash affects all services)
  • No independent scaling
  • Resource contention
  • Debugging complexity

The AI summary references SHARED_CLASSLOADING_ISSUES.txt which likely documents some concerns—consider summarizing key points here for visibility.

📋 Suggested section to add
## ⚠️ Limitations & Considerations

This is a proof-of-concept deployment strategy with significant trade-offs:

- **No service isolation**: All services share the same JVM, classloader, and resources
- **Single point of failure**: If Tomcat crashes, all services go down
- **Dependency conflicts**: Shared classpath can cause version conflicts (see SHARED_CLASSLOADING_ISSUES.txt)
- **No independent scaling**: Cannot scale individual services based on load
- **Security boundaries**: Services share the same security context

**Use case**: Development/testing environments where resource efficiency is prioritized over production-grade isolation.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/README.md` around lines 1 - 59, Add a new
"Limitations & Trade-offs" section to docker-compose/multiwar/README.md that
concisely documents architectural drawbacks of the multi-WAR approach: mention
shared classloader risks (dependency conflicts, refer to
SHARED_CLASSLOADING_ISSUES.txt), single point of failure (one Tomcat/JVM for all
services), no independent scaling or per-service resource limits, increased
debugging complexity and weakened security boundaries, and recommend this
strategy only for dev/testing; also note how to enable/disable services via the
MANIFEST array in war-deploy.sh for operational context.

14-24: 💤 Low value

Add language identifier to fenced code block.

The ASCII diagram should specify a language identifier for proper rendering. Use text for ASCII art.

📝 Proposed fix
-```
+```text
 Original server (unmodified)          Wrapper project (generated)
 ┌─────────────────────────┐          ┌─────────────────────────┐

As per coding guidelines, the static analysis tool markdownlint-cli2 flagged: "Fenced code blocks should have a language specified (MD040)".

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/README.md` around lines 14 - 24, The fenced ASCII
diagram block in the README lacks a language identifier; update the diagram's
code fence to use the text language by changing the opening fence from ``` to
```text (and keep the closing fence ```), so the ASCII art (the "Original server
(unmodified) ... report-server.war" diagram) is rendered correctly and satisfies
MD040.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docker-compose/multiwar/docker-compose.multiwar.yml`:
- Around line 12-13: The comment incorrectly states that the mounted server.xml
configures Host startStopThreads="10" for parallel WAR deployment; update the
comment to reflect the actual configuration and reasoning by noting that
docker-compose/multiwar/server.xml sets startStopThreads="1" (sequential) to
avoid Logback ConcurrentModificationException described in
SHARED_CLASSLOADING_ISSUES.txt and implemented in wars.sh; change the comment
above the volume mount to accurately describe that server.xml enforces
sequential deployment via startStopThreads="1" and reference the wars.sh
behavior and ISSUE 4 rationale so future readers understand the intentional
sequential setting.
- Around line 38-41: The entrypoint's Elasticsearch wait loop (the entrypoint
array that runs curl and then catalina.sh run) can hang forever; change it to
bound the wait with a max retry count or a timeout so the script exits non‑zero
if ES doesn't become healthy; implement a loop that increments attempts (or use
timeout) and after N failures logs an error and exits before calling
catalina.sh, ensuring the container can restart or fail fast instead of hanging
indefinitely.

In `@docker-compose/multiwar/nonwars-to-tomcat-config/common-application.yml`:
- Around line 29-30: Update the config-server base-uri entry in
common-application.yml to include a trailing slash so URI concatenation works
correctly; specifically change the config-server: base-uri (the value used by
UriComponentsBuilder.fromUriString) from "http://config-server:80" to
"http://config-server:80/". This will ensure relative paths like "v1/..." are
appended correctly (e.g., config-server.base-uri).

In `@docker-compose/multiwar/README.md`:
- Line 51: Update the section header "## Excluded (Boot WebFlux —
incompatible(??) with WAR)" by removing the uncertainty markers and making the
incompatibility definitive; replace it with a clear statement such as "##
Excluded (Spring Boot WebFlux — not compatible with WAR packaging)" so the
README unambiguously reflects the documented limitation of WebFlux and WAR
packaging.

In `@docker-compose/multiwar/SHARED_CLASSLOADING_ISSUES.txt`:
- Around line 134-143: The ISSUE numbering is inconsistent: the header reads
"ISSUE 10" while the bullet items are labeled "8a/8b/8c"; update the identifiers
to be consistent by either changing the header to "ISSUE 8" or renumbering the
sub-items to "10a/10b/10c" (and update any cross-references or indexes that
mention these IDs), ensuring the header and each sub-item label match (e.g.,
header "ISSUE 10" with sub-items "10a/10b/10c" or vice versa) so readers and
tooling won't be confused.

In `@docker-compose/multiwar/wars.sh`:
- Around line 3-14: The header block at the top of wars.sh still says
"war-deploy.sh" which is stale; update the header comment to reference the
actual script name "wars.sh" (and any internal references like usage lines
showing "./war-deploy.sh") and also adjust the --help handler that prints those
header lines so it emits the corrected script name; search for the header
comment text and the "--help" handler logic in wars.sh and replace occurrences
of "war-deploy.sh" with "wars.sh" (or parameterize the script name from $0) so
the help output matches the real filename.
- Around line 191-199: The code only strips a single trailing whitespace from
the parsed name (variable key), so CRs or multiple trailing spaces can remain;
update the trimming to remove all trailing whitespace/CR characters when
populating gridsuite_services. Replace the current `${key%%[[:space:]]}` with a
full-trim approach (for example, enable extglob and use `${key%%+([[:space:]])}`
or pipe key through `sed 's/[[:space:]]\+$//'`) and apply it in both places
where key is set so gridsuite_services receives clean keys.

---

Nitpick comments:
In `@docker-compose/multiwar/docker-compose.multiwar.yml`:
- Around line 53-152: Extract the repeated common service configuration
(JAVA_TOOL_OPTIONS, command, sysctls, memswap_limit, deploy.resources.limits)
into a YAML anchor (e.g. &svc-defaults) placed near the top of the services
block, then reference it in each service (config-server,
config-notification-server, study-notification-server,
directory-notification-server, gateway) using the merge key (<<: *svc-defaults);
ensure the anchor contains the exact keys to be shared and keep service-specific
keys like image, ports, volumes and any extra mounts outside the merged block so
each service still overrides or extends as needed.
- Around line 6-10: The tomcat service currently uses a floating tag "image:
tomcat:10.1-jdk21" which must be pinned by digest for reproducibility; locate
the tomcat service block (the "tomcat" service and the "image:
tomcat:10.1-jdk21" line) and replace the tag with the corresponding
digest-pinned reference (e.g., "tomcat@sha256:<digest>") obtained from the
Docker registry (docker pull or manifest inspect) so the
docker-compose.multiwar.yml uses an immutable image reference.

In `@docker-compose/multiwar/README.md`:
- Line 3: Remove the user-facing AI generation attribution line "Generated with
little supervision by opus4.6." from the README content so the documentation no
longer references the generation method; if you need to retain provenance, add
that note to the commit message or an internal comment in the repo instead.
- Around line 1-59: Add a new "Limitations & Trade-offs" section to
docker-compose/multiwar/README.md that concisely documents architectural
drawbacks of the multi-WAR approach: mention shared classloader risks
(dependency conflicts, refer to SHARED_CLASSLOADING_ISSUES.txt), single point of
failure (one Tomcat/JVM for all services), no independent scaling or per-service
resource limits, increased debugging complexity and weakened security
boundaries, and recommend this strategy only for dev/testing; also note how to
enable/disable services via the MANIFEST array in war-deploy.sh for operational
context.
- Around line 14-24: The fenced ASCII diagram block in the README lacks a
language identifier; update the diagram's code fence to use the text language by
changing the opening fence from ``` to ```text (and keep the closing fence ```),
so the ASCII art (the "Original server (unmodified) ... report-server.war"
diagram) is rendered correctly and satisfies MD040.

In `@docker-compose/multiwar/wars.sh`:
- Around line 496-509: The loop reading dependencies uses an unused variable `t`
and should be renamed to `_` in the while-read that constructs `shared_deps_xml`
(look for the while IFS=: read -r g a t classifier v; do ... done <
"$deps_dir/_shared.txt") to silence shellcheck; remove or stop assigning the
unused `SHARED_DEPS_FILE` variable (search for its assignment around the 530
area) since it’s never used; and quote the parameter expansion
`${propfile#$res_dir/}` (used later where propfile is stripped of $res_dir) to
prevent accidental globbing by changing to a quoted form so the pattern is
treated literally.
- Around line 451-453: The use of grep -oP is not portable; replace the grep+sed
step with a POSIX-compatible awk that extracts the first non-space token from
each line of "$deps_file" before piping to the existing awk/ sort sequence. For
example, change the pipeline that starts with grep -oP '^\s+\S+' "$deps_file" to
use awk '{ if (match($0,/^[[:space:]]*[^[:space:]]+/)) print
substr($0,RSTART,RLENGTH) }' "$deps_file" | awk -F: 'NF==5 {print
$1":"$2":"$3"::"$4} NF>=6 {print $1":"$2":"$3":"$4":"$5}' | sort -u >
"$deps_dir/${ctx}.parsed", keeping the same variables deps_file, deps_dir and
ctx so the rest of wars.sh remains unchanged.
- Around line 285-370: The function add_shared_lib_autoconfig_exclusions relies
on DEPS_DIR but DEPS_DIR is only set inside find_common_deps, causing
unbound-variable failures when functions are invoked out of order; to fix,
declare and initialize DEPS_DIR alongside the other top-level path globals at
the top of the script (so DEPS_DIR exists even before find_common_deps runs) and
then remove the later assignment to DEPS_DIR from find_common_deps; update
references to DEPS_DIR in add_shared_lib_autoconfig_exclusions and
find_common_deps as needed to ensure the single authoritative initialization is
at the module scope.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: edc9c00b-ef27-4e3b-bd1a-452aec713251

📥 Commits

Reviewing files that changed from the base of the PR and between 359fc74 and 1b13abb.

📒 Files selected for processing (9)
  • docker-compose/multiwar/.env
  • docker-compose/multiwar/README.md
  • docker-compose/multiwar/SHARED_CLASSLOADING_ISSUES.txt
  • docker-compose/multiwar/docker-compose.multiwar.yml
  • docker-compose/multiwar/docker-compose.yml
  • docker-compose/multiwar/itools-config.yml
  • docker-compose/multiwar/nonwars-to-tomcat-config/common-application.yml
  • docker-compose/multiwar/server.xml
  • docker-compose/multiwar/wars.sh

Comment on lines +12 to +13
# Custom server.xml: sets Host startStopThreads="10" for parallel WAR deployment
- ./server.xml:/usr/local/tomcat/conf/server.xml:Z
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Comment contradicts the mounted server.xml.

The comment claims server.xml sets Host startStopThreads="10" for parallel WAR deployment, but docker-compose/multiwar/server.xml line 37 uses startStopThreads="1" (sequential), and the script header in wars.sh plus SHARED_CLASSLOADING_ISSUES.txt (ISSUE 4) explicitly explain why sequential deployment is required to avoid the Logback ConcurrentModificationException.

🔧 Proposed fix
-      # Custom server.xml: sets Host startStopThreads="10" for parallel WAR deployment
+      # Custom server.xml: sets Host startStopThreads="1" for sequential WAR deployment
+      # (parallel deployment races on the shared Logback LoggerContext — see
+      # SHARED_CLASSLOADING_ISSUES.txt, Issue 4).
       - ./server.xml:/usr/local/tomcat/conf/server.xml:Z

Also applies to: 35-37

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/docker-compose.multiwar.yml` around lines 12 - 13,
The comment incorrectly states that the mounted server.xml configures Host
startStopThreads="10" for parallel WAR deployment; update the comment to reflect
the actual configuration and reasoning by noting that
docker-compose/multiwar/server.xml sets startStopThreads="1" (sequential) to
avoid Logback ConcurrentModificationException described in
SHARED_CLASSLOADING_ISSUES.txt and implemented in wars.sh; change the comment
above the volume mount to accurately describe that server.xml enforces
sequential deployment via startStopThreads="1" and reference the wars.sh
behavior and ISSUE 4 rationale so future readers understand the intentional
sequential setting.

Comment on lines +38 to +41
# Wait for elasticsearch before starting Tomcat: WARs that depend on elasticsearch
# (study-server, directory-server, case-server, network-conversion-server) fail
# immediately if ES is not reachable at startup (no built-in retry).
entrypoint: ["/bin/bash", "-c", "cp /shared-lib/*.jar /usr/local/tomcat/lib/ 2>/dev/null; until curl -sf http://elasticsearch:9200/_cluster/health; do echo 'Waiting for elasticsearch...'; sleep 3; done && catalina.sh run"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Confirm curl is available in the base image.
docker run --rm tomcat:10.1-jdk21 sh -c 'command -v curl && curl --version | head -1' 2>&1 || true

Repository: gridsuite/deployment

Length of output: 109


🌐 Web query:

tomcat 10.1-jdk21 curl available installed

💡 Result:

Yes—Tomcat 10.1 can be run with Java 21 (JDK21). Apache Tomcat 10.1 is designed to run on Java 11 and later [1], so Java 21 is within the supported range [2]. (A related point from release notes: Tomcat 10.1 includes support for virtual threads, which are Java 21+ only.) [3] Tomcat 10.1 is available for download as a binary distribution from the official downloads page [4] (with archives available for older releases) [4]. For example, the Apache distribution site provides version directories like v10.1.54 and includes download files and packaging details [5]. If by “curl available installed” you mean “download it with curl and install”: the official page emphasizes verifying release integrity using the provided OpenPGP signatures and/or SHA-512 checksums after downloading [4]. Example curl download (replace VERSION and MIRROR as appropriate): 1) Pick your target release directory (e.g., v10.1.54) [5]. 2) Download the binary archive from that directory using curl. Note: The exact URL for the tar/zip depends on the chosen Tomcat version and packaging type (e.g., apache-tomcat-VERSION.tar.gz) [5]. For an “installed” option, you can also use the official Tomcat Docker image tag naming scheme that includes JDK21—for example the docker-library project defines a Tomcat 10.1 JDK21-based image using FROM eclipse-temurin:21-jdk-jammy with TOMCAT_VERSION set (example shown for 10.1.54) [6]. The existence of such tags indicates straightforward availability of a JDK21 runtime environment for Tomcat 10.1 [6].

Citations:


🏁 Script executed:

# Check if there's an elasticsearch service definition in the repo with healthcheck
find . -name "*.yml" -o -name "*.yaml" | head -20

Repository: gridsuite/deployment

Length of output: 1016


🏁 Script executed:

# Look for elasticsearch service definition and healthchecks
rg -t yaml "elasticsearch" --max-count=20

Repository: gridsuite/deployment

Length of output: 3687


🏁 Script executed:

# Get the elasticsearch service definition with context
sed -n '/^  elasticsearch:/,/^  [^ ]/p' docker-compose/technical/docker-compose.technical.yml | head -40

Repository: gridsuite/deployment

Length of output: 572


🏁 Script executed:

# Check multiwar compose file for service dependencies
cat -n docker-compose/multiwar/docker-compose.multiwar.yml | head -60

Repository: gridsuite/deployment

Length of output: 3950


🌐 Web query:

eclipse-temurin:21-jdk-jammy curl available

💡 Result:

Yes—eclipse-temurin:21-jdk-jammy includes curl. The official Adoptium/Eclipse Temurin container Dockerfile for 21/jdk on Ubuntu jammy explicitly installs curl via apt-get (and documents it as “curl required for historical reasons”).[1] The Docker Hub “eclipse-temurin” image documentation also notes that when you run the container and add certificates, they are available for “curl and other CLI tools,” implying curl is present in the image.[2] If you still want to verify in your environment, run inside the container: docker run --rm -it eclipse-temurin:21-jdk-jammy sh -lc 'command -v curl && curl --version'

Citations:


Elasticsearch wait loop has no timeout and will hang indefinitely.

until curl -sf http://elasticsearch:9200/_cluster/health; do sleep 3; done retries forever. If ES never comes up (bad config, image pull issue, OOM), the Tomcat container hangs in the entrypoint indefinitely and restart: unless-stopped won't help — the process never exits. Bound retries to prevent hanging:

Suggested fix
-    entrypoint: ["/bin/bash", "-c", "cp /shared-lib/*.jar /usr/local/tomcat/lib/ 2>/dev/null; until curl -sf http://elasticsearch:9200/_cluster/health; do echo 'Waiting for elasticsearch...'; sleep 3; done && catalina.sh run"]
+    entrypoint:
+      - /bin/bash
+      - -c
+      - |
+        cp /shared-lib/*.jar /usr/local/tomcat/lib/ 2>/dev/null
+        for i in $(seq 1 60); do
+          curl -sf http://elasticsearch:9200/_cluster/health && break
+          echo "Waiting for elasticsearch... ($i/60)"
+          sleep 3
+        done
+        curl -sf http://elasticsearch:9200/_cluster/health || { echo "Elasticsearch never became ready"; exit 1; }
+        exec catalina.sh run
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# Wait for elasticsearch before starting Tomcat: WARs that depend on elasticsearch
# (study-server, directory-server, case-server, network-conversion-server) fail
# immediately if ES is not reachable at startup (no built-in retry).
entrypoint: ["/bin/bash", "-c", "cp /shared-lib/*.jar /usr/local/tomcat/lib/ 2>/dev/null; until curl -sf http://elasticsearch:9200/_cluster/health; do echo 'Waiting for elasticsearch...'; sleep 3; done && catalina.sh run"]
# Wait for elasticsearch before starting Tomcat: WARs that depend on elasticsearch
# (study-server, directory-server, case-server, network-conversion-server) fail
# immediately if ES is not reachable at startup (no built-in retry).
entrypoint:
- /bin/bash
- -c
- |
cp /shared-lib/*.jar /usr/local/tomcat/lib/ 2>/dev/null
for i in $(seq 1 60); do
curl -sf http://elasticsearch:9200/_cluster/health && break
echo "Waiting for elasticsearch... ($i/60)"
sleep 3
done
curl -sf http://elasticsearch:9200/_cluster/health || { echo "Elasticsearch never became ready"; exit 1; }
exec catalina.sh run
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/docker-compose.multiwar.yml` around lines 38 - 41,
The entrypoint's Elasticsearch wait loop (the entrypoint array that runs curl
and then catalina.sh run) can hang forever; change it to bound the wait with a
max retry count or a timeout so the script exits non‑zero if ES doesn't become
healthy; implement a loop that increments attempts (or use timeout) and after N
failures logs an error and exits before calling catalina.sh, ensuring the
container can restart or fail fast instead of hanging indefinitely.

Comment on lines +29 to +30
config-server:
base-uri: http://config-server:80
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Find how gridsuite.services.config-server.base-uri is consumed across the
# backend servers. If the same UriComponentsBuilder.fromUriString pattern is
# used as for the other services, the trailing slash matters.
rg -nP -C3 'config-server' --type=java | rg -nP -C3 'base[-_]?uri|baseUri|@Value\s*\(' | head -200
rg -nP -C3 'fromUriString' --type=java | head -100

Repository: gridsuite/deployment

Length of output: 362


🏁 Script executed:

#!/bin/bash
# First, explore the repository structure to understand layout
echo "=== Repository structure ==="
find . -maxdepth 2 -type f -name "*.sh" | head -20
find . -maxdepth 3 -type d -name "src" -o -type d -name "java"
ls -la | head -30

Repository: gridsuite/deployment

Length of output: 742


🏁 Script executed:

#!/bin/bash
# Find the wars.sh file mentioned in the review
find . -name "wars.sh" -type f

Repository: gridsuite/deployment

Length of output: 98


🏁 Script executed:

#!/bin/bash
# Search for config-server references broadly without type filter
rg -i 'config-server' --type-list | head -5
rg 'config-server' -C3 | head -100

Repository: gridsuite/deployment

Length of output: 7823


🏁 Script executed:

#!/bin/bash
# Search for how base-uri properties are used across the codebase
rg 'base-uri|base_uri|baseUri' -C2 | head -150

Repository: gridsuite/deployment

Length of output: 12368


🏁 Script executed:

#!/bin/bash
# Search for how gridsuite.services.config-server is consumed in the codebase
# Look for `@Value`, `@ConfigurationProperties`, or any config-server property usage
rg 'gridsuite\.services\.config-server|config.?server.*base' -i --type=yml --type=yaml | head -50

Repository: gridsuite/deployment

Length of output: 92


🏁 Script executed:

#!/bin/bash
# Look for how services.config-server or base-uri values are injected/used
# Search in property files and Java code
rg 'services\.config-server|\.base-uri|baseUri' -i | head -100

Repository: gridsuite/deployment

Length of output: 182


🏁 Script executed:

#!/bin/bash
# Check wars.sh more carefully to understand context of resolve_base_uri
cat docker-compose/multiwar/wars.sh | head -200

Repository: gridsuite/deployment

Length of output: 10010


🏁 Script executed:

#!/bin/bash
# Look for config-server references in application-local files
find . -name "application-local.*" -type f | xargs grep -l "config-server" 2>/dev/null | head -20

Repository: gridsuite/deployment

Length of output: 46


🏁 Script executed:

#!/bin/bash
# Check the full common-application.yml file to see context and structure
cat docker-compose/multiwar/nonwars-to-tomcat-config/common-application.yml

Repository: gridsuite/deployment

Length of output: 2141


🏁 Script executed:

#!/bin/bash
# Search for how config-server is actually consumed (look for `@Value` or property injection)
rg 'config-server|gridsuite\.services' | grep -v '.git' | head -100

Repository: gridsuite/deployment

Length of output: 5895


Add trailing slash to config-server base-uri.

The config-server entry in common-application.yml is missing a trailing slash: http://config-server:80 instead of http://config-server:80/. All other services in this file (and wars.sh documentation at lines 119–123) confirm that clients use UriComponentsBuilder.fromUriString(baseUri) which concatenates relative paths directly after the base URI. Without the trailing slash, http://config-server:80 + v1/... becomes http://config-server:80v1/... (broken).

🔧 Proposed fix
     config-server:
-      base-uri: http://config-server:80
+      base-uri: http://config-server:80/
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
config-server:
base-uri: http://config-server:80
config-server:
base-uri: http://config-server:80/
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/nonwars-to-tomcat-config/common-application.yml`
around lines 29 - 30, Update the config-server base-uri entry in
common-application.yml to include a trailing slash so URI concatenation works
correctly; specifically change the config-server: base-uri (the value used by
UriComponentsBuilder.fromUriString) from "http://config-server:80" to
"http://config-server:80/". This will ensure relative paths like "v1/..." are
appended correctly (e.g., config-server.base-uri).

- Maven 3.8+
- Server submodules checked out and buildable in the layout of Gridsuite Aggregator

## Excluded (Boot WebFlux — incompatible(??) with WAR)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Description: Check WebFlux dependencies in excluded servers to verify incompatibility claims

echo "Checking for WebFlux dependencies in excluded servers..."
for server in config-server config-notification-server directory-notification-server \
              merge-notification-server study-notification-server gateway; do
  if [ -d "../../../${server}" ]; then
    echo "=== ${server} ==="
    fd -e xml -e gradle pom.xml build.gradle --exec rg -l "spring-boot-starter-webflux|spring-webflux"
  fi
done

Repository: gridsuite/deployment

Length of output: 121


🏁 Script executed:

# Explore the repository structure
git ls-files | head -30

Repository: gridsuite/deployment

Length of output: 1210


🏁 Script executed:

# Check the main directory structure
ls -la

Repository: gridsuite/deployment

Length of output: 713


🏁 Script executed:

# Look for build files that would indicate where services are defined
fd -e "pom.xml" -e "build.gradle" -o -e "docker-compose.yml" | head -20

Repository: gridsuite/deployment

Length of output: 181


🏁 Script executed:

# Read the multiwar README to understand context
cat docker-compose/multiwar/README.md

Repository: gridsuite/deployment

Length of output: 1830


🏁 Script executed:

# Check if any service source code or configs are in this repo that might reference WebFlux
rg -i "webflux|spring-boot-starter-web" --type markdown --type yml

Repository: gridsuite/deployment

Length of output: 92


🌐 Web query:

Spring Boot WebFlux WAR packaging compatibility servlet container

💡 Result:

Spring Boot WebFlux applications are not compatible with WAR packaging for deployment to servlet containers. Official Spring Boot documentation explicitly states: "Because Spring WebFlux does not strictly depend on the Servlet API and applications are deployed by default on an embedded Reactor Netty server, War deployment is not supported for WebFlux applications."[1][2][3][4]. This position is consistent across versions, including recent 3.3.x documentation[2][4], and Spring Boot team members have confirmed no plans to support it due to technical challenges like requiring Servlet 3.1+ with async I/O and risks of mixing blocking/non-blocking code[5][6]. Spring Boot recommends packaging WebFlux apps as executable JARs with embedded Netty[5][6]. While plain Spring Framework WebFlux supports WAR deployment via AbstractReactiveWebInitializer on Servlet 3.1+ containers[7][8][9], this is not integrated with Spring Boot's auto-configuration and leads to errors or unsupported behavior when attempted[5][10][11][12]. No changes noted as of 2026[13][14].

Citations:


🌐 Web query:

Spring Cloud Config Server WebFlux Spring Cloud Gateway architecture

💡 Result:

Spring Cloud Config Server WebFlux + Spring Cloud Gateway: how the architecture typically fits together (and where WebFlux can be tricky). 1) What each component is (and what protocol it speaks) - Spring Cloud Config Server exposes an HTTP resource-based API for external configuration (name/value pairs or YAML) and is embeddable in a Spring Boot app using @EnableConfigServer. It runs as a Spring Boot application (default port 8080; commonly 8888). [1] - Spring Cloud Gateway Server WebFlux is a reactive (Spring WebFlux/Project Reactor) gateway; its configuration (routes, predicates, filters) is driven by RouteDefinitionLocator/RouteDefinition and routes are matched via Spring WebFlux HandlerMapping infrastructure. [2][3][4] 2) Canonical “centralized config + reactive gateway” architecture A typical setup is: - Config Server (Spring Boot app): backs centralized config and serves it over HTTP. - Gateway (Spring Cloud Gateway on WebFlux): routes incoming client requests to downstream services (often discovered via Eureka, though that’s a separate concern). Gateway is itself reactive and expects WebFlux runtime semantics. [2][4][3] - Each downstream microservice (including Gateway itself if desired) is a Config Client: it fetches its own configuration from Config Server at startup using the Config Client support (connects to Config Server via spring.cloud.config.uri or spring.config.import=optional:configserver:...). [5][6] Key idea: Config Server is not “wired into” Gateway request routing at the WebFlux layer; instead, it provides configuration to the apps that need it (Gateway and downstream services). Config Server is an HTTP backend for configuration, not a routing component for Gateway. [1][5] 3) Where “Config Server + WebFlux” can be confusing - If you add Spring WebFlux starter(s) to Config Server, you may run into servlet-vs-reactive controller differences. A Stack Overflow report notes that the Config Server ResourceController can rely on ServletWebRequest, and therefore may not work properly with a reactive stack out of the box. [7] So for production-grade architectures, treat Config Server as a server that provides an HTTP API for config, and ensure its own web stack/controller compatibility matches the Spring Cloud Config version you’re using (don’t assume that adding spring-boot-starter-webflux will automatically make every endpoint reactive). [7][1] 4) How Gateway configuration relates to Config Server - Spring Cloud Gateway’s route configuration is driven by route definitions (RouteDefinitionLocator) and can be provided via properties (default PropertiesRouteDefinitionLocator loads from Spring Boot @ConfigurationProperties). [3] - Therefore, the most common approach is: a) Put Gateway route settings (e.g., spring.cloud.gateway.routes.* or equivalent RouteLocator configuration) in the config repository. b) Have the Gateway application fetch those settings from Config Server as part of its normal Config Client startup. This keeps Gateway reactive (it still runs on WebFlux) while config is supplied via the Config Server’s HTTP API. [3][1][5] 5) A concrete “wiring” pattern (conceptual) - Config Server: serves configuration artifacts for each application name/profile over HTTP. [1] - Gateway app: starts, connects to Config Server, loads properties (including Gateway route/predicate/filter config), then starts routing requests reactively. [5][3][4] If you tell me your exact versions (Spring Boot + Spring Cloud release train + Spring Cloud Config/Gateway versions) and whether you want Gateway routes to come from Config Server Git files or from discovery/database, I can draft an example application.yml/bootstrapping layout for both Config Server and Gateway.

Citations:


Remove the uncertainty markers from the WebFlux incompatibility statement.

The exclusion is correct and well-documented: Spring Boot officially does not support WAR packaging for WebFlux applications because WebFlux depends on an embedded Reactor Netty server and does not integrate with the Servlet API. Replace the "(??) " with a definitive statement since this is a documented limitation, not an uncertain one.

Consider updating to: "Excluded (Spring Boot WebFlux — not compatible with WAR packaging)"

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/README.md` at line 51, Update the section header "##
Excluded (Boot WebFlux — incompatible(??) with WAR)" by removing the uncertainty
markers and making the incompatibility definitive; replace it with a clear
statement such as "## Excluded (Spring Boot WebFlux — not compatible with WAR
packaging)" so the README unambiguously reflects the documented limitation of
WebFlux and WAR packaging.

Comment on lines +134 to +143
ISSUE 10: Maven build failures
─────────────────────────────
8a) Thread contention: -T2.0C (40 threads on 20 cores) caused Maven lock
contention. Fixed: -T4.
8b) Missing artifact com.bea.xml:jsr173-ri:1.0 (transitive of stax-utils).
Fixed: wildcard <exclusions> on all shared-deps POM entries since
_shared.txt is already the full transitive closure.
8c) Empty WARs: packagingExcludes=WEB-INF/lib/*.jar removed everything.
maven-war-plugin doesn't support ! negation in packagingExcludes.
Fixed: switched to packagingIncludes (whitelist approach).
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

ISSUE numbering mismatch.

The header says "ISSUE 10" but the sub-items below are labeled 8a / 8b / 8c.

🔧 Proposed fix
 ISSUE 10: Maven build failures
 ─────────────────────────────
-8a) Thread contention: -T2.0C (40 threads on 20 cores) caused Maven lock
+10a) Thread contention: -T2.0C (40 threads on 20 cores) caused Maven lock
     contention. Fixed: -T4.
-8b) Missing artifact com.bea.xml:jsr173-ri:1.0 (transitive of stax-utils).
+10b) Missing artifact com.bea.xml:jsr173-ri:1.0 (transitive of stax-utils).
     Fixed: wildcard <exclusions> on all shared-deps POM entries since
     _shared.txt is already the full transitive closure.
-8c) Empty WARs: packagingExcludes=WEB-INF/lib/*.jar removed everything.
+10c) Empty WARs: packagingExcludes=WEB-INF/lib/*.jar removed everything.
     maven-war-plugin doesn't support ! negation in packagingExcludes.
     Fixed: switched to packagingIncludes (whitelist approach).
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/SHARED_CLASSLOADING_ISSUES.txt` around lines 134 -
143, The ISSUE numbering is inconsistent: the header reads "ISSUE 10" while the
bullet items are labeled "8a/8b/8c"; update the identifiers to be consistent by
either changing the header to "ISSUE 8" or renumbering the sub-items to
"10a/10b/10c" (and update any cross-references or indexes that mention these
IDs), ensuring the header and each sub-item label match (e.g., header "ISSUE 10"
with sub-items "10a/10b/10c" or vice versa) so readers and tooling won't be
confused.

Comment on lines +3 to +14
# war-deploy.sh — Build GridSuite microservices as WAR files for docker-compose.
# Zero modifications to original server source files.
#
# Word of Caution, the whole script with comments (except this sentence)
# has been generated by opus4.6 without much look at the details.
#
# Usage:
# ./war-deploy.sh [OPTIONS]
#
# Options:
# --only SRV Only process this server (repeatable)
# --help Show this help
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Stale filename in header comment.

The header refers to war-deploy.sh, but the file is named wars.sh. The --help handler (line 56) also extracts these lines verbatim, so users will see the wrong command name.

🔧 Proposed fix
-# war-deploy.sh — Build GridSuite microservices as WAR files for docker-compose.
+# wars.sh — Build GridSuite microservices as WAR files for docker-compose.
 #                 Zero modifications to original server source files.
 ...
 # Usage:
-#   ./war-deploy.sh [OPTIONS]
+#   ./wars.sh [OPTIONS]
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
# war-deploy.sh — Build GridSuite microservices as WAR files for docker-compose.
# Zero modifications to original server source files.
#
# Word of Caution, the whole script with comments (except this sentence)
# has been generated by opus4.6 without much look at the details.
#
# Usage:
# ./war-deploy.sh [OPTIONS]
#
# Options:
# --only SRV Only process this server (repeatable)
# --help Show this help
# wars.sh — Build GridSuite microservices as WAR files for docker-compose.
# Zero modifications to original server source files.
#
# Word of Caution, the whole script with comments (except this sentence)
# has been generated by opus4.6 without much look at the details.
#
# Usage:
# ./wars.sh [OPTIONS]
#
# Options:
# --only SRV Only process this server (repeatable)
# --help Show this help
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/wars.sh` around lines 3 - 14, The header block at the
top of wars.sh still says "war-deploy.sh" which is stale; update the header
comment to reference the actual script name "wars.sh" (and any internal
references like usage lines showing "./war-deploy.sh") and also adjust the
--help handler that prints those header lines so it emits the corrected script
name; search for the header comment text and the "--help" handler logic in
wars.sh and replace occurrences of "war-deploy.sh" with "wars.sh" (or
parameterize the script name from $0) so the help output matches the real
filename.

Comment on lines +191 to +199
if [[ "$line" =~ ^[[:space:]]+-[[:space:]]*name:[[:space:]]*(.+) ]]; then
local key="${BASH_REMATCH[1]}"
key="${key%%[[:space:]]}"
[[ "$current_section" == "gridsuite" ]] && gridsuite_services+=("$key")
elif [[ "$line" =~ ^[[:space:]]+name:[[:space:]]*(.+) && "$current_section" == "gridsuite" ]]; then
local key="${BASH_REMATCH[1]}"
key="${key%%[[:space:]]}"
gridsuite_services+=("$key")
fi
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Trailing-whitespace trim only strips a single character.

${key%%[[:space:]]} uses a glob pattern (not a regex), and [[:space:]] is a single-character class — so even with %% this removes at most one trailing whitespace. Trailing CR (e.g., CRLF files) or multiple spaces will leak into the YAML key list and later URI generation.

🔧 Proposed fix
-        if [[ "$line" =~ ^[[:space:]]+-[[:space:]]*name:[[:space:]]*(.+) ]]; then
-            local key="${BASH_REMATCH[1]}"
-            key="${key%%[[:space:]]}"
+        if [[ "$line" =~ ^[[:space:]]+-[[:space:]]*name:[[:space:]]*(.+) ]]; then
+            local key="${BASH_REMATCH[1]}"
+            key="${key%"${key##*[![:space:]]}"}"
             [[ "$current_section" == "gridsuite" ]] && gridsuite_services+=("$key")
         elif [[ "$line" =~ ^[[:space:]]+name:[[:space:]]*(.+) && "$current_section" == "gridsuite" ]]; then
             local key="${BASH_REMATCH[1]}"
-            key="${key%%[[:space:]]}"
+            key="${key%"${key##*[![:space:]]}"}"
             gridsuite_services+=("$key")
         fi
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if [[ "$line" =~ ^[[:space:]]+-[[:space:]]*name:[[:space:]]*(.+) ]]; then
local key="${BASH_REMATCH[1]}"
key="${key%%[[:space:]]}"
[[ "$current_section" == "gridsuite" ]] && gridsuite_services+=("$key")
elif [[ "$line" =~ ^[[:space:]]+name:[[:space:]]*(.+) && "$current_section" == "gridsuite" ]]; then
local key="${BASH_REMATCH[1]}"
key="${key%%[[:space:]]}"
gridsuite_services+=("$key")
fi
if [[ "$line" =~ ^[[:space:]]+-[[:space:]]*name:[[:space:]]*(.+) ]]; then
local key="${BASH_REMATCH[1]}"
key="${key%"${key##*[![:space:]]}"}"
[[ "$current_section" == "gridsuite" ]] && gridsuite_services+=("$key")
elif [[ "$line" =~ ^[[:space:]]+name:[[:space:]]*(.+) && "$current_section" == "gridsuite" ]]; then
local key="${BASH_REMATCH[1]}"
key="${key%"${key##*[![:space:]]}"}"
gridsuite_services+=("$key")
fi
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose/multiwar/wars.sh` around lines 191 - 199, The code only strips
a single trailing whitespace from the parsed name (variable key), so CRs or
multiple trailing spaces can remain; update the trimming to remove all trailing
whitespace/CR characters when populating gridsuite_services. Replace the current
`${key%%[[:space:]]}` with a full-trim approach (for example, enable extglob and
use `${key%%+([[:space:]])}` or pipe key through `sed 's/[[:space:]]\+$//'`) and
apply it in both places where key is set so gridsuite_services receives clean
keys.

@jonenst jonenst marked this pull request as draft May 11, 2026 10:45
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant