mirror of
https://github.com/GTNewHorizons/GTNH-Actions-Workflows.git
synced 2026-09-01 03:47:30 +02:00
Full Pack tests against latest daily w. dependency-aware actions (#66)
Co-authored-by: UltraProdigy <187078471+UltraProdigy@users.noreply.github.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
||||
#!/usr/bin/env bash
|
||||
# Server side of the integration run: starts the server, lets it settle, then
|
||||
# stops it cleanly and records the exit code for later verification.
|
||||
#
|
||||
# This script does not decide whether a run was good. That is verified later by
|
||||
# verify_server.sh, which reads the outputs produced here (server.log and the
|
||||
# exit-code flag).
|
||||
#
|
||||
# Base logic moved here from https://github.com/MalTeeez/packscripts-auto-builds/blob/gtnh-daily/packaging/scripts/entrypoint.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SERVER_DIR="${SERVER_DIR:-/home/gtnh}"
|
||||
RUN_DIR="${RUN_DIR:-$SERVER_DIR}"
|
||||
|
||||
SERVER_LOG="$RUN_DIR/server.log"
|
||||
SERVER_EXIT_FLAG="${SERVER_EXIT_FLAG:-$RUN_DIR/server.exit}"
|
||||
SERVER_READY_FLAG="${SERVER_READY_FLAG:-$RUN_DIR/server.ready}"
|
||||
|
||||
RCON_HOST="${RCON_HOST:-localhost}"
|
||||
RCON_PORT="${RCON_PORT:-25575}"
|
||||
RCON_PASSWORD="${RCON_PASSWORD:-whoahaplaintextpassword}"
|
||||
|
||||
SERVER_JAVA_ARGS="${SERVER_JAVA_ARGS:--Xms1G -Xmx2G -Dfml.readTimeout=5 @java9args.txt -jar lwjgl3ify-forgePatches.jar nogui}"
|
||||
|
||||
START_TIMEOUT="${SERVER_START_TIMEOUT:-240}"
|
||||
SETTLE_DURATION="${SERVER_SETTLE_DURATION:-30}"
|
||||
STOP_TIMEOUT="${SERVER_STOP_TIMEOUT:-20}"
|
||||
|
||||
SERVER_PID=""
|
||||
TAIL_PID=""
|
||||
|
||||
cleanup() {
|
||||
[ -n "$TAIL_PID" ] && kill "$TAIL_PID" 2>/dev/null
|
||||
# If we still hold the JVM (e.g. an early failure), don't leak it into the runner.
|
||||
[ -n "$SERVER_PID" ] && kill -0 "$SERVER_PID" 2>/dev/null && kill "$SERVER_PID" 2>/dev/null
|
||||
return 0
|
||||
}
|
||||
|
||||
stop_and_reap() {
|
||||
( sleep "$STOP_TIMEOUT"; kill -9 "$SERVER_PID" 2>/dev/null ) &
|
||||
local killer=$!
|
||||
local code=0
|
||||
wait "$SERVER_PID" || code=$?
|
||||
kill "$killer" 2>/dev/null
|
||||
SERVER_PID=""
|
||||
echo "$code" > "$SERVER_EXIT_FLAG"
|
||||
echo "server exited with code $code"
|
||||
}
|
||||
|
||||
trap cleanup EXIT INT TERM
|
||||
|
||||
run() {
|
||||
# SERVER_JAVA_ARGS can arrive as a multi-line string. Split it on whitespace
|
||||
# into a proper argv array so the launch below stays happy.
|
||||
local java_args=()
|
||||
local arg
|
||||
for arg in $SERVER_JAVA_ARGS; do
|
||||
java_args+=("$arg")
|
||||
done
|
||||
|
||||
mkdir -p "$RUN_DIR"
|
||||
rm -f "$SERVER_EXIT_FLAG" "$SERVER_READY_FLAG"
|
||||
|
||||
cd "$SERVER_DIR"
|
||||
sed -i 's|eula=false|eula=true|g' eula.txt
|
||||
sed -i "s|enable-rcon=false|enable-rcon=true\nrcon.password=${RCON_PASSWORD}\nrcon.port=${RCON_PORT}|" server.properties
|
||||
sed -i 's|online-mode=true|online-mode=false|' server.properties
|
||||
|
||||
# Backgrounded and logged to a file so we can watch startup while the JVM runs.
|
||||
java "${java_args[@]}" > "$SERVER_LOG" 2>&1 &
|
||||
SERVER_PID=$!
|
||||
|
||||
tail -n +1 -F "$SERVER_LOG" 2>/dev/null &
|
||||
TAIL_PID=$!
|
||||
|
||||
local waited=0
|
||||
while [ "$waited" -lt "$START_TIMEOUT" ]; do
|
||||
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||
echo "server exited unexpectedly during startup"
|
||||
return
|
||||
fi
|
||||
if grep -q 'Done.*For help, type' "$SERVER_LOG" 2>/dev/null; then
|
||||
echo "server started after ${waited}s"
|
||||
: > "$SERVER_READY_FLAG"
|
||||
break
|
||||
fi
|
||||
sleep 5
|
||||
waited=$((waited + 5))
|
||||
done
|
||||
|
||||
if [ ! -e "$SERVER_READY_FLAG" ]; then
|
||||
echo "server did not become ready within ${START_TIMEOUT}s"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "waiting ${SETTLE_DURATION}s for server to settle..."
|
||||
sleep "$SETTLE_DURATION"
|
||||
|
||||
if ! kill -0 "$SERVER_PID" 2>/dev/null; then
|
||||
echo "server exited during settling"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "stopping server via rcon"
|
||||
rcon-cli --host "$RCON_HOST" --port "$RCON_PORT" --password "$RCON_PASSWORD" stop
|
||||
|
||||
stop_and_reap
|
||||
}
|
||||
|
||||
# Run the lifecycle without aborting on a server-side failure - capturing the
|
||||
# exit code is the whole point, so verify_server.sh can judge the run.
|
||||
run || true
|
||||
|
||||
# run bailed early with the JVM still up so stop it too
|
||||
if [ -n "$SERVER_PID" ]; then
|
||||
kill "$SERVER_PID" 2>/dev/null || true
|
||||
stop_and_reap
|
||||
fi
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
JSON_FILE=$1
|
||||
GRADLE_DIR=~/.gradle
|
||||
INIT_GRADLE=$GRADLE_DIR/init.gradle
|
||||
|
||||
# Exit early if there are no dependencies
|
||||
DEP_COUNT=$(jq '.dependencies | length' "$JSON_FILE")
|
||||
if [ "$DEP_COUNT" -eq 0 ]; then
|
||||
echo "No dependencies found, failure was probably not due to a required dependency. Failing to propagate initial failure."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Write init.gradle header to user gradle dir
|
||||
# (first as a temp file since it will parsed w. just this)
|
||||
mkdir -p $GRADLE_DIR
|
||||
cat > $INIT_GRADLE.tmp << 'EOF'
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
}
|
||||
configurations.all {
|
||||
resolutionStrategy.eachDependency { details ->
|
||||
EOF
|
||||
|
||||
# Process each dependency
|
||||
jq -c '.dependencies[]' $JSON_FILE | while read -r dep; do
|
||||
JAR_PATH=$(echo $dep | jq -r '.jar_path')
|
||||
REPO_URL=$(echo $dep | jq -r '.repo_url')
|
||||
COMMIT_SHA=$(echo $dep | jq -r '.commit_sha')
|
||||
|
||||
PREV_DIR=$(pwd)
|
||||
REPO_NAME=$(basename $REPO_URL .git)
|
||||
WORK_DIR=$(mktemp -d)/$REPO_NAME
|
||||
mkdir -p $WORK_DIR
|
||||
echo "Processing $REPO_URL @ $COMMIT_SHA (in $WORK_DIR)"
|
||||
cd $WORK_DIR
|
||||
|
||||
# Shallow clone and checkout
|
||||
git init .
|
||||
git remote add origin $REPO_URL
|
||||
git fetch --depth 1 origin $COMMIT_SHA
|
||||
git fetch --tags --depth 1
|
||||
git checkout $COMMIT_SHA
|
||||
|
||||
# Get coordinates
|
||||
PROPS=$(./gradlew -q :properties 2>/dev/null < /dev/null)
|
||||
GROUP=$(echo "$PROPS" | grep '^group:' | awk '{print $2}')
|
||||
# Gradle does not actually seem to have project name,
|
||||
# it just takes the project folder name (in this case, the repo)
|
||||
PROJECT=$REPO_NAME
|
||||
# We don't actually care about the version, we just want to override it (this just returns a short sha rn)
|
||||
# If we ever do care about it, we need to figure out how to get it with just a shallow clone
|
||||
VERSION=$(echo "$PROPS" | grep '^version:' | awk '{print $2}')-local
|
||||
|
||||
echo "Coordinates of local maven result: $GROUP:$PROJECT:$VERSION"
|
||||
|
||||
# Generate a pom for local maven (need to do this, so we have deps included)
|
||||
VERSION=$VERSION ./gradlew generatePomFileForMavenPublication < /dev/null
|
||||
|
||||
# Setup local maven
|
||||
MAVEN_PATH="${GROUP//.//}/$PROJECT/$VERSION"
|
||||
mkdir -p ~/.m2/repository/$MAVEN_PATH
|
||||
|
||||
# Copy in pom and create fake normal jar so gradle is happy
|
||||
mv ./build/publications/maven/pom-default.xml ~/.m2/repository/$MAVEN_PATH/$PROJECT-$VERSION.pom
|
||||
touch ~/.m2/repository/$MAVEN_PATH/$PROJECT-$VERSION.jar
|
||||
|
||||
# Go back to original dir & clean up workdir
|
||||
cd $PREV_DIR
|
||||
rm -rf $WORK_DIR
|
||||
|
||||
# Move actual jar to local maven
|
||||
cp $JAR_PATH ~/.m2/repository/$MAVEN_PATH/$PROJECT-$VERSION-dev.jar
|
||||
|
||||
# Append override to init.gradle
|
||||
cat >> $INIT_GRADLE.tmp << EOF
|
||||
if (details.requested.module.toString() == '${GROUP}:${PROJECT}') {
|
||||
details.useVersion '${VERSION}'
|
||||
details.because 'PR dependency override'
|
||||
}
|
||||
EOF
|
||||
|
||||
rm -rf $WORK_DIR
|
||||
done
|
||||
|
||||
# Close init.gradle
|
||||
cat >> $INIT_GRADLE.tmp << 'EOF'
|
||||
}
|
||||
}
|
||||
}
|
||||
EOF
|
||||
|
||||
# Rename to actual now that its parseable
|
||||
mv $INIT_GRADLE.tmp $INIT_GRADLE
|
||||
@@ -0,0 +1,87 @@
|
||||
#!/usr/bin/env bash
|
||||
# Checks whether the server side of the integration run passed
|
||||
#
|
||||
# adjusted from the full DAXXL version
|
||||
#
|
||||
# No `set -e`: greps that legitimately find nothing must not be mistaken for
|
||||
# failures. Each check feeds the explicit status instead, so every problem of
|
||||
# the run gets reported, not just the first one.
|
||||
set -uo pipefail
|
||||
shopt -s nullglob
|
||||
|
||||
RUN_DIR="${RUN_DIR:?RUN_DIR must be set}"
|
||||
SERVER_DIR="${SERVER_DIR:?SERVER_DIR must be set}"
|
||||
|
||||
SERVER_LOG="$RUN_DIR/server.log"
|
||||
SERVER_EXIT_FLAG="${SERVER_EXIT_FLAG:-$RUN_DIR/server.exit}"
|
||||
|
||||
rc=0
|
||||
|
||||
# Sets a non-zero exit code, with the provided reason
|
||||
fail() {
|
||||
echo "FAIL: $*"
|
||||
rc=1
|
||||
}
|
||||
|
||||
# Exit code recorded by server.sh when the JVM stopped
|
||||
if [ -e "$SERVER_EXIT_FLAG" ]; then
|
||||
exit_code=$(cat "$SERVER_EXIT_FLAG")
|
||||
else
|
||||
exit_code=missing
|
||||
fi
|
||||
echo "server exit code: $exit_code"
|
||||
[ "$exit_code" = "0" ] || fail "server exited with non-zero code: $exit_code"
|
||||
|
||||
# Crash reports
|
||||
crash_reports=("$SERVER_DIR/crash-reports/crash"*.txt)
|
||||
if [ "${#crash_reports[@]}" -gt 0 ]; then
|
||||
latest_crash_report="${crash_reports[-1]}"
|
||||
fail "found server crash report at ${latest_crash_report##*/}:"
|
||||
cat "$latest_crash_report"
|
||||
fi
|
||||
|
||||
# JVM fatal error logs
|
||||
hs_err_logs=("$SERVER_DIR/hs_err_pid"*.log)
|
||||
if [ "${#hs_err_logs[@]}" -gt 0 ]; then
|
||||
latest_hs_err="${hs_err_logs[-1]}"
|
||||
fail "JVM fatal error log detected ${latest_hs_err##*/}:"
|
||||
cat "$latest_hs_err"
|
||||
fi
|
||||
|
||||
if [ -r "$SERVER_LOG" ]; then
|
||||
if grep --quiet --fixed-strings 'Fatal errors were detected' "$SERVER_LOG"; then
|
||||
fail "fatal errors detected:"
|
||||
grep -n --fixed-strings 'Fatal errors were detected' "$SERVER_LOG"
|
||||
fi
|
||||
|
||||
if grep --quiet --fixed-strings 'The state engine was in incorrect state ERRORED and forced into state SERVER_STOPPED' \
|
||||
"$SERVER_LOG"; then
|
||||
fail "server force stopped:"
|
||||
grep -n --fixed-strings 'The state engine was in incorrect state ERRORED and forced into state SERVER_STOPPED' "$SERVER_LOG"
|
||||
fi
|
||||
|
||||
# Duplicate mods only count when the two jar names in the line differ;
|
||||
# a mod colliding with itself is just a jar being seen twice.
|
||||
if grep --quiet --fixed-strings 'Duplicate mod found:' "$SERVER_LOG"; then
|
||||
dupes=$(grep --fixed-strings 'Duplicate mod found:' "$SERVER_LOG" \
|
||||
| while read -r line || [ -n "$line" ]; do
|
||||
a=$(echo "$line" | grep -oP '(?<=\()[^)]+\.jar(?=\))' | head -1)
|
||||
b=$(echo "$line" | grep -oP '(?<=\()[^)]+\.jar(?=\))' | tail -1)
|
||||
[ "$a" != "$b" ] && echo "$line" || true
|
||||
done)
|
||||
if [ -n "$dupes" ]; then
|
||||
fail "server had duplicate files, environment cant be guaranteed to contain correct versions:"
|
||||
echo "$dupes"
|
||||
fi
|
||||
fi
|
||||
|
||||
if grep --quiet --fixed-strings 'Exception stopping the server' "$SERVER_LOG"; then
|
||||
fail "server didn't shut down cleanly:"
|
||||
grep -n --fixed-strings 'Exception stopping the server' "$SERVER_LOG"
|
||||
fi
|
||||
else
|
||||
fail "server log missing or unreadable: $SERVER_LOG"
|
||||
fi
|
||||
|
||||
[ "$rc" -eq 0 ] && echo "SERVER: pass" || echo "SERVER: fail"
|
||||
exit "$rc"
|
||||
Reference in New Issue
Block a user