Development: Try to fix client 404 error on testservers#13141
Conversation
Development: Try to fix that client 404 error on testserversDevelopment: Try to fix client 404 error on testservers
WalkthroughThe ChangesGradle Build Configuration
Estimated code review effort: 1 (Trivial) | ~5 minutes 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (1)
gradle/profile_prod.gradle (1)
29-29: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value
args = ["-v"]invokes pnpm for no apparent purpose.When
skipWebappis set,args = ["-v"]still runspnpm -vbefore the real work happens indoLast. If this is only there to satisfyPnpmTask's requirement for a non-emptyargs, a short comment would help future readers understand why an unrelated pnpm invocation exists in the skip path.🤖 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 `@gradle/profile_prod.gradle` at line 29, The skipWebapp branch in the PnpmTask configuration uses args = ["-v"] only to satisfy the task’s non-empty args requirement, so add a brief explanatory comment near that assignment in the profile_prod.gradle task setup. Reference the task/block where skipWebapp is checked and doLast is used, and make it clear that the pnpm -v call is intentional and not part of the real build work.
🤖 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 `@gradle/profile_prod.gradle`:
- Around line 25-38: The prod task only declares the static output directory and
misses the frontend inputs that the dev profile tracks, so the task can stay
stale when webapp sources or the skipWebapp branch changes. Update the task in
profile_prod.gradle (the same task block that sets outputs.dir and args) to
declare the missing inputs for pnpm-lock.yaml, angular.json, tsconfig*.json,
src/main/webapp/, and the skipWebapp property, matching the dependency tracking
used in profile_dev.gradle.
- Around line 30-35: The webapp asset copy in the `doLast` block currently
treats a missing or empty `build/webapp-dist` as a no-op, which lets packaging
continue with an empty static output. Update the `copy` step in
`profile_prod.gradle` to explicitly verify the source exists and contains files
before copying, and fail the build with an error if it is absent or empty. Use
the `doLast`/`copy` logic around `build/webapp-dist` and
`build/resources/main/static/` as the place to add this check.
---
Nitpick comments:
In `@gradle/profile_prod.gradle`:
- Line 29: The skipWebapp branch in the PnpmTask configuration uses args =
["-v"] only to satisfy the task’s non-empty args requirement, so add a brief
explanatory comment near that assignment in the profile_prod.gradle task setup.
Reference the task/block where skipWebapp is checked and doLast is used, and
make it clear that the pnpm -v call is intentional and not part of the real
build work.
🪄 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: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: a24e0f54-03e2-4c14-9bb6-c772f3589299
⛔ Files ignored due to path filters (1)
.github/workflows/ci-build.ymlis excluded by!**/*.yml
📒 Files selected for processing (1)
gradle/profile_prod.gradle
| outputs.dir("build/resources/main/static/") | ||
| .withPropertyName("webapp-build-dir") | ||
|
|
||
| if (project.hasProperty("skipWebapp")) { | ||
| args = ["-v"] | ||
| doLast { | ||
| copy { | ||
| from "build/webapp-dist" | ||
| into "build/resources/main/static/" | ||
| } | ||
| } | ||
| } else { | ||
| args = ["run", "webapp:prod"] | ||
| } |
There was a problem hiding this comment.
🚀 Performance & Scalability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== profile_prod.gradle ==\n'
nl -ba gradle/profile_prod.gradle | sed -n '1,120p'
printf '\n== references to build/resources/main/static and build/webapp-dist ==\n'
rg -n "build/resources/main/static|build/webapp-dist|skipWebapp|webapp:prod|outputs\.dir|inputs\." -S .
printf '\n== task type definition if present ==\n'
rg -n "class .*PnpmTask|PnpmTask" -S gradle . || true
printf '\n== related build files ==\n'
git ls-files | rg '(^|/)(war\.gradle|profile_prod\.gradle|build\.gradle|settings\.gradle|angular\.json|package\.json)$'Repository: ls1intum/Artemis
Length of output: 221
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== gradle/profile_prod.gradle ==\n'
cat -n gradle/profile_prod.gradle | sed -n '1,160p'
printf '\n== references to build/resources/main/static, build/webapp-dist, skipWebapp, webapp:prod, outputs.dir, inputs. ==\n'
rg -n -S "build/resources/main/static|build/webapp-dist|skipWebapp|webapp:prod|outputs\.dir|inputs\." .
printf '\n== PnpmTask definition ==\n'
rg -n -S "class .*PnpmTask|PnpmTask" gradle . || true
printf '\n== related build files ==\n'
git ls-files | rg '(^|/)(war\.gradle|profile_prod\.gradle|build\.gradle|settings\.gradle|angular\.json|package\.json)$'Repository: ls1intum/Artemis
Length of output: 11807
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== gradle/profile_dev.gradle (webapp task section) ==\n'
sed -n '35,80p' gradle/profile_dev.gradle | cat -n
printf '\n== PnpmTask definition / usage ==\n'
rg -n -S "PnpmTask|abstract class .*PnpmTask|class .*PnpmTask|task.*PnpmTask" build.gradle gradle . --glob '!**/build/**'
printf '\n== skipWebapp / build-webapp-dist producers ==\n'
rg -n -S "skipWebapp|build/webapp-dist|webapp-dist" . --glob '!**/build/**'
printf '\n== angular build output target ==\n'
sed -n '1,90p' angular.json | cat -nRepository: ls1intum/Artemis
Length of output: 7969
🏁 Script executed:
#!/bin/bash
set -euo pipefail
printf '\n== skipWebapp / webapp-dist references across repo ==\n'
rg -n -S "skipWebapp|webapp-dist|build/webapp-dist" . --glob '!**/build/**' --glob '!**/dist/**'
printf '\n== build.gradle around PnpmTask wiring ==\n'
sed -n '640,720p' build.gradle | cat -n
printf '\n== profile_prod.gradle and profile_dev.gradle webapp tasks ==\n'
sed -n '18,40p' gradle/profile_prod.gradle | cat -n
printf '\n---\n'
sed -n '9,33p' gradle/profile_dev.gradle | cat -nRepository: ls1intum/Artemis
Length of output: 6009
Add the missing webapp inputs to the prod task.
gradle/profile_prod.gradle only declares outputs.dir(...); unlike gradle/profile_dev.gradle, it doesn’t track pnpm-lock.yaml, angular.json, tsconfig*.json, src/main/webapp/, or skipWebapp. That can leave build/resources/main/static/ stale when frontend sources or the task branch changes.
🤖 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 `@gradle/profile_prod.gradle` around lines 25 - 38, The prod task only declares
the static output directory and misses the frontend inputs that the dev profile
tracks, so the task can stay stale when webapp sources or the skipWebapp branch
changes. Update the task in profile_prod.gradle (the same task block that sets
outputs.dir and args) to declare the missing inputs for pnpm-lock.yaml,
angular.json, tsconfig*.json, src/main/webapp/, and the skipWebapp property,
matching the dependency tracking used in profile_dev.gradle.
| doLast { | ||
| copy { | ||
| from "build/webapp-dist" | ||
| into "build/resources/main/static/" | ||
| } | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Inspect the target file and nearby build logic.
git ls-files gradle/profile_prod.gradle
wc -l gradle/profile_prod.gradle
cat -n gradle/profile_prod.gradle | sed -n '1,160p'
# Look for any validation around webapp-dist or static asset packaging.
rg -n "webapp-dist|skipWebapp|resources/main/static|copy \\{" gradle . -g '!**/build/**'Repository: ls1intum/Artemis
Length of output: 4323
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Find where this Gradle profile is applied and whether bootJar has any related inputs/outputs.
rg -n "profile_prod\.gradle|skipWebapp|bootJar|webapp-dist|build/resources/main/static" -g '!**/build/**' .
# Inspect any other Gradle files that may affect bootJar/resource packaging.
git ls-files '*.gradle' '*.gradle.kts'Repository: ls1intum/Artemis
Length of output: 3185
🌐 Web query:
Gradle Copy task missing source directory behavior doLast bootJar copy from missing directory
💡 Result:
When a Gradle Copy task specifies a source directory that does not exist, the task typically treats the source as empty [1]. Because no files are found to copy, Gradle marks the task as "NO-SOURCE" and skips its execution without throwing an error [1][2]. If you are using a copy block inside a doLast action (e.g., within a bootJar task or a custom task), the behavior differs: 1. Copy Task Behavior: If you define a formal task of type Copy, Gradle evaluates the source paths during the configuration phase [3]. If the directory is missing, it is simply skipped [1]. 2. doLast { copy {... } } Behavior: When calling the project.copy method inside a doLast block, the copy operation is executed imperatively at runtime [3]. If the source directory specified in the from method does not exist at that moment, the copy method may fail or behave unpredictably (sometimes throwing a NullPointerException or simply doing nothing depending on the Gradle version and implementation) [4]. To handle missing source directories gracefully, you should ensure the existence of the source directory before attempting the copy, or use logic to verify the path: Example solution: task copyTask(type: Copy) { def sourceDir = file('path/to/source') if (sourceDir.exists) { from sourceDir into 'destination/dir' } else { doFirst { logger.warn("Source directory $sourceDir does not exist, skipping copy.") } } } For Spring Boot's bootJar task, you should interact with its configuration (e.g., using the bootInf method) to include files rather than relying on a doLast copy block, as this ensures your build remains compatible with Gradle's incremental build and up-to-date checks [5][6]. Using doLast for file manipulation often bypasses Gradle's task dependencies and input/output tracking, which can lead to non-deterministic build results [3][7].
Citations:
- 1: https://stackoverflow.com/questions/28130067/fail-gradle-copy-task-if-source-directory-not-exist
- 2: https://discuss.gradle.org/t/gradle-copy-task-stopped-working-at-some-point-with-no-source/42362
- 3: https://stackoverflow.com/questions/40505629/gradle-copy-task-not-copying-files-from-temp-folder-first-time-around
- 4: https://discuss.gradle.org/t/project-copy-within-dolast-throws-nullpointerexception/14683
- 5: https://docs.spring.io/spring-boot/gradle-plugin/api/java/org/springframework/boot/gradle/tasks/bundling/BootJar.html
- 6: https://docs.spring.io/spring-boot/3.5/gradle-plugin/api/java/org/springframework/boot/gradle/tasks/bundling/BootJar.html
- 7: https://discuss.gradle.org/t/copy-task-not-working/42047
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import urllib.request
url = "https://docs.gradle.org/current/dsl/org.gradle.api.tasks.Copy.html"
try:
with urllib.request.urlopen(url, timeout=10) as r:
text = r.read(5000).decode("utf-8", "replace")
print(text[:2000])
except Exception as e:
print(type(e).__name__, e)
PYRepository: ls1intum/Artemis
Length of output: 297
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import urllib.request, re
urls = [
"https://docs.gradle.org/current/userguide/more_about_tasks.html",
"https://docs.gradle.org/current/userguide/authoring_tasks.html",
]
for url in urls:
try:
with urllib.request.urlopen(url, timeout=15) as r:
txt = r.read().decode("utf-8", "replace")
print("URL", url, "OK", len(txt))
for needle in ["doLast", "task actions", "actions"]:
if needle in txt:
print(" contains", needle)
print(txt[:500].replace("\n"," ")[:500])
except Exception as e:
print("URL", url, type(e).__name__, e)
PYRepository: ls1intum/Artemis
Length of output: 575
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import urllib.request, re
url = "https://docs.gradle.org/current/userguide/more_about_tasks.html"
txt = urllib.request.urlopen(url, timeout=15).read().decode("utf-8", "replace")
for needle in ["doLast", "doFirst", "Task actions", "Actions are executed", "executed in order"]:
idx = txt.find(needle)
print(f"\n== {needle} @ {idx} ==")
if idx != -1:
print(re.sub(r"<[^>]+>", " ", txt[max(0, idx-300):idx+700])[:1000])
PYRepository: ls1intum/Artemis
Length of output: 2748
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import urllib.request, re
url = "https://docs.gradle.org/current/userguide/working_with_files.html"
txt = urllib.request.urlopen(url, timeout=15).read().decode("utf-8", "replace")
for needle in ["copy", "missing", "nonexistent", "from(", "empty"]:
idx = txt.lower().find(needle.lower())
print(f"\n== {needle} @ {idx} ==")
if idx != -1:
print(re.sub(r"<[^>]+>", " ", txt[max(0, idx-300):idx+900])[:1200])
PYRepository: ls1intum/Artemis
Length of output: 2748
🏁 Script executed:
#!/bin/bash
set -euo pipefail
python3 - <<'PY'
import urllib.request, re
url = "https://docs.gradle.org/current/userguide/working_with_files.html"
txt = urllib.request.urlopen(url, timeout=15).read().decode("utf-8", "replace")
needle = "If the source path of a file copy action resolves to a file that does not exist"
idx = txt.find(needle)
print("idx", idx)
print(re.sub(r"<[^>]+>", " ", txt[idx-500:idx+900]))
PYRepository: ls1intum/Artemis
Length of output: 2748
🏁 Script executed:
#!/bin/bash
set -euo pipefail
# Compare the production profile with the dev profile to understand intended behavior.
wc -l gradle/profile_dev.gradle gradle/profile_prod.gradle
cat -n gradle/profile_dev.gradle | sed -n '1,140p'Repository: ls1intum/Artemis
Length of output: 3268
Fail fast when build/webapp-dist is absent. copy { from "build/webapp-dist" } treats a missing source dir as empty, so webapp still succeeds and processResources packages an empty build/resources/main/static/ tree. That ships the jar without the webapp assets; throw here if the dist is missing or empty.
🤖 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 `@gradle/profile_prod.gradle` around lines 30 - 35, The webapp asset copy in
the `doLast` block currently treats a missing or empty `build/webapp-dist` as a
no-op, which lets packaging continue with an empty static output. Update the
`copy` step in `profile_prod.gradle` to explicitly verify the source exists and
contains files before copying, and fail the build with an error if it is absent
or empty. Use the `doLast`/`copy` logic around `build/webapp-dist` and
`build/resources/main/static/` as the place to add this check.
End-to-End Test Results
Test Strategy: Two-phase execution
|
bbf0de0 to
821298e
Compare
|
@matyasht Your PR description needs attention before it can be reviewed: Issues Found
How to Fix
This check validates that your PR description follows the PR template. A complete description helps reviewers understand your changes and speeds up the review process.
|
Summary
Checklist
General
Server
Client
authoritiesto all new routes and checked the course groups for displaying navigation elements (links, buttons).Changes affecting Programming Exercises
Motivation and Context
Description
Steps for Testing
Prerequisites:
Exam Mode Testing
Prerequisites:
Testserver States
You can manage test servers using Helios. Check environment statuses in the environment list. To deploy to a test server, go to the CI/CD page, find your PR or branch, and trigger the deployment.
Review Progress
Performance Review
Code Review
Manual Tests
Exam Mode Test
Performance Tests
Test Coverage
No code changes detected - test coverage not required for this PR.
Last updated: 2026-07-05 18:17:55 UTC
Screenshots
Summary by CodeRabbit