mirror of
https://github.com/GTNewHorizons/GTNH-Actions-Workflows.git
synced 2026-07-15 20:39:58 +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:
parent
2c3a2c1ff9
commit
219d11877b
36
.github/workflows/build-and-test.yml
vendored
36
.github/workflows/build-and-test.yml
vendored
@ -46,6 +46,11 @@ on:
|
|||||||
required: false
|
required: false
|
||||||
default: false
|
default: false
|
||||||
type: boolean
|
type: boolean
|
||||||
|
external-deps-inclusion:
|
||||||
|
description: 'Enable usage of external dependency artifacts that might have been provided by trigger-rebuild-with-deps (if installed)'
|
||||||
|
required: false
|
||||||
|
default: false
|
||||||
|
type: boolean
|
||||||
|
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
|
||||||
@ -72,6 +77,37 @@ jobs:
|
|||||||
path: .gtnh-workflows
|
path: .gtnh-workflows
|
||||||
fetch-depth: 0
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Find external-deps artifact for this run
|
||||||
|
id: find-artifact
|
||||||
|
if: ${{ inputs.external-deps-inclusion }}
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# The artifact is named after this run's ID because try-rebuild-with-deps runs in the
|
||||||
|
# master context; filtering by head_sha would never match the PR's SHA (I tried).
|
||||||
|
# Reruns keep the same run_id, so this name is stable across attempts.
|
||||||
|
RUN_ID=$(gh api \
|
||||||
|
"repos/${{ github.repository }}/actions/artifacts?name=external-deps-${{ github.run_id }}" \
|
||||||
|
--jq ".artifacts[0].workflow_run.id // empty")
|
||||||
|
echo "run_id=$RUN_ID" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Download external deps
|
||||||
|
if: ${{ inputs.external-deps-inclusion && steps.find-artifact.outputs.run_id != '' }}
|
||||||
|
uses: actions/download-artifact@v8
|
||||||
|
with:
|
||||||
|
name: external-deps-${{ github.run_id }}
|
||||||
|
path: ./.packscripts/
|
||||||
|
run-id: ${{ steps.find-artifact.outputs.run_id }}
|
||||||
|
github-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
|
||||||
|
- name: Install external deps to local maven
|
||||||
|
if: ${{ inputs.external-deps-inclusion && hashFiles('./.packscripts/**') != '' }}
|
||||||
|
run: |
|
||||||
|
echo "Aquired build artifacts from rebuild job: " && ls -lahR ./.packscripts/
|
||||||
|
bash .gtnh-workflows/scripts/upload-deps-to-localmaven.sh ./.packscripts/required_prs.json
|
||||||
|
echo "Overriding dependencies of project with versions from local maven:" && cat ~/.gradle/init.gradle
|
||||||
|
echo "Contents of local maven:" && ls -lahR ~/.m2/repository/com/github
|
||||||
|
|
||||||
- name: Determine JDK versions
|
- name: Determine JDK versions
|
||||||
id: list-jdk-versions
|
id: list-jdk-versions
|
||||||
shell: bash
|
shell: bash
|
||||||
|
|||||||
22
.github/workflows/gate-by-required.yml
vendored
Normal file
22
.github/workflows/gate-by-required.yml
vendored
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
name: Check state of other required PRs
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-required-prs:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check required PRs
|
||||||
|
uses: MalTeeez/packscripts@a89fe398d047ac9e2e165465a51096be4f9853cb
|
||||||
|
env:
|
||||||
|
NO_COLOR: 1
|
||||||
|
with:
|
||||||
|
command: >-
|
||||||
|
pr gate ${{ github.event.pull_request.html_url }}
|
||||||
|
--build_job "Build and test"
|
||||||
|
--other_allowed_owner "GTNewHorizons"
|
||||||
|
--allow_all_merged
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
config: https://raw.githubusercontent.com/MalTeeez/packscripts-auto-builds/refs/heads/gtnh-daily/packscripts.json
|
||||||
|
annotated_file: https://raw.githubusercontent.com/MalTeeez/packscripts-auto-builds/refs/heads/gtnh-daily/annotated_mods.json
|
||||||
172
.github/workflows/latest-daily-integration-test.yml
vendored
Normal file
172
.github/workflows/latest-daily-integration-test.yml
vendored
Normal file
@ -0,0 +1,172 @@
|
|||||||
|
name: Test integration in latest daily
|
||||||
|
|
||||||
|
# Note: this reusable workflow must called from a context that is triggered by a "Build and test" run (which then propagates the event)
|
||||||
|
# That context requires workflow_run, which runs in the context of the default branch,
|
||||||
|
# therefore we use the statuses api to place it on the source commit manually here
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
statuses: write
|
||||||
|
|
||||||
|
# Key on the triggering build's head_sha so each PR head is isolated, and a
|
||||||
|
# repaired rerun (same run_id, same head_sha, new attempt) cancels the now-stale
|
||||||
|
# in-flight run for that head instead of racing it to post a status
|
||||||
|
concurrency:
|
||||||
|
group: ${{ github.workflow }}-${{ github.event.workflow_run.head_sha }}
|
||||||
|
cancel-in-progress: true
|
||||||
|
|
||||||
|
env:
|
||||||
|
STATUS_CONTEXT: "Test in latest daily"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
get-pr-url:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
# Run on ANY pull_request build completion. We branch on conclusion below
|
||||||
|
if: github.event.workflow_run.event == 'pull_request'
|
||||||
|
outputs:
|
||||||
|
pr_url: ${{ steps.lookup.outputs.url }}
|
||||||
|
conclusion: ${{ github.event.workflow_run.conclusion }}
|
||||||
|
steps:
|
||||||
|
- name: Look up PR url
|
||||||
|
id: lookup
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
PR_URL=$(gh api \
|
||||||
|
"repos/${{ github.repository }}/commits/${{ github.event.workflow_run.head_sha }}/pulls" \
|
||||||
|
--jq "[.[] | select(.head.sha == \"${{ github.event.workflow_run.head_sha }}\" and .state == \"open\")] | first | .html_url // empty")
|
||||||
|
|
||||||
|
if [ -z "$PR_URL" ]; then
|
||||||
|
echo "Failed to find a PR url"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
# Pending only on the path where the real test is about to run
|
||||||
|
- name: Mark status pending on PR commit
|
||||||
|
if: github.event.workflow_run.conclusion == 'success'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh api -X POST \
|
||||||
|
"repos/${{ github.repository }}/statuses/${{ github.event.workflow_run.head_sha }}" \
|
||||||
|
-f state="pending" \
|
||||||
|
-f context="$STATUS_CONTEXT" \
|
||||||
|
-f description="Running integration test in latest daily…" \
|
||||||
|
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
|
|
||||||
|
full-pack-test:
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
needs: get-pr-url
|
||||||
|
# Real test work runs ONLY on a successful build
|
||||||
|
if: needs.get-pr-url.outputs.conclusion == 'success'
|
||||||
|
name: Test in latest daily
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: ghcr.io/malteeez/gtnh-daily:latest
|
||||||
|
env:
|
||||||
|
PR_URL: ${{ needs.get-pr-url.outputs.pr_url }}
|
||||||
|
SERVER_DIR: /home/gtnh
|
||||||
|
RUN_DIR: /home/gtnh
|
||||||
|
SERVER_EXIT_FLAG: /home/gtnh/server.exit
|
||||||
|
steps:
|
||||||
|
- name: Checkout workflows repo
|
||||||
|
uses: actions/checkout@v7
|
||||||
|
with:
|
||||||
|
repository: GTNewHorizons/GTNH-Actions-Workflows
|
||||||
|
ref: ${{ job.workflow_sha }}
|
||||||
|
sparse-checkout:
|
||||||
|
scripts/
|
||||||
|
path: .gtnh-workflows
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Install libc so we can run our binary on alpine
|
||||||
|
run: apk add --no-cache libstdc++ libgcc
|
||||||
|
|
||||||
|
- name: Check out PR build artifact
|
||||||
|
uses: MalTeeez/packscripts@a89fe398d047ac9e2e165465a51096be4f9853cb
|
||||||
|
env:
|
||||||
|
NO_COLOR: 1
|
||||||
|
with:
|
||||||
|
command: >-
|
||||||
|
pr apply $PR_URL
|
||||||
|
--build_job "Build and test"
|
||||||
|
--artifact_name "build-libs"
|
||||||
|
--other_allowed_owner "GTNewHorizons"
|
||||||
|
--pack_variant "server"
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
working_directory: /home/gtnh
|
||||||
|
musl: true
|
||||||
|
|
||||||
|
- name: Run server
|
||||||
|
timeout-minutes: 30
|
||||||
|
run: bash .gtnh-workflows/scripts/server.sh
|
||||||
|
|
||||||
|
- name: Verify server
|
||||||
|
if: success() || failure()
|
||||||
|
run: bash .gtnh-workflows/scripts/verify_server.sh
|
||||||
|
|
||||||
|
report:
|
||||||
|
needs: [get-pr-url, full-pack-test]
|
||||||
|
# Post a terminal status for every pull_request build, independent of get-pr-url's
|
||||||
|
# result, so a superseding run always clears a stale pending on the source commit
|
||||||
|
if: always() && github.event.workflow_run.event == 'pull_request'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
# Backstop for the cancel-in-progress race on a repaired rerun. Attempt 1 and
|
||||||
|
# attempt 2 of the triggering build share one run_id but differ in run_attempt,
|
||||||
|
# and both target the SAME commit's status slot. If this run is processing an
|
||||||
|
# earlier attempt than the build's current one, it's stale — bail so a late
|
||||||
|
# attempt-1 result can't clobber the attempt-2 result on the context.
|
||||||
|
- name: Bail if a newer attempt of the triggering build exists
|
||||||
|
id: stalecheck
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
TRIGGER_RUN_ID="${{ github.event.workflow_run.id }}"
|
||||||
|
MY_ATTEMPT="${{ github.event.workflow_run.run_attempt }}"
|
||||||
|
LATEST_ATTEMPT=$(gh api \
|
||||||
|
"repos/${{ github.repository }}/actions/runs/${TRIGGER_RUN_ID}" \
|
||||||
|
--jq '.run_attempt' 2>/dev/null || true)
|
||||||
|
echo "::notice::trigger run ${TRIGGER_RUN_ID} — mine=${MY_ATTEMPT} latest=${LATEST_ATTEMPT}"
|
||||||
|
if [ -z "$LATEST_ATTEMPT" ]; then
|
||||||
|
# Couldn't read the triggering run — fail open, let the post proceed.
|
||||||
|
echo "stale=false" >> "$GITHUB_OUTPUT"
|
||||||
|
elif [ "$MY_ATTEMPT" -lt "$LATEST_ATTEMPT" ]; then
|
||||||
|
echo "::notice::Attempt ${MY_ATTEMPT} superseded by attempt ${LATEST_ATTEMPT}; not posting status."
|
||||||
|
echo "stale=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "stale=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Report final status to PR commit
|
||||||
|
if: steps.stalecheck.outputs.stale == 'false'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
CONCL="${{ github.event.workflow_run.conclusion }}"
|
||||||
|
TEST_RESULT="${{ needs.full-pack-test.result }}"
|
||||||
|
if [ "$CONCL" != "success" ]; then
|
||||||
|
STATE="failure"
|
||||||
|
DESC="Build failed; integration test not run"
|
||||||
|
elif [ "$TEST_RESULT" = "success" ]; then
|
||||||
|
STATE="success"
|
||||||
|
DESC="Integration test complete"
|
||||||
|
elif [ "$TEST_RESULT" = "skipped" ]; then
|
||||||
|
STATE="error"
|
||||||
|
DESC="Could not resolve PR; integration test not run"
|
||||||
|
else
|
||||||
|
STATE="failure"
|
||||||
|
DESC="Integration test failed"
|
||||||
|
fi
|
||||||
|
gh api -X POST \
|
||||||
|
"repos/${{ github.repository }}/statuses/${{ github.event.workflow_run.head_sha }}" \
|
||||||
|
-f state="$STATE" \
|
||||||
|
-f context="$STATUS_CONTEXT" \
|
||||||
|
-f description="$DESC" \
|
||||||
|
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
104
.github/workflows/trigger-rebuild-with-deps.yml
vendored
Normal file
104
.github/workflows/trigger-rebuild-with-deps.yml
vendored
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
name: Trigger a rebuild with externally required PRs
|
||||||
|
|
||||||
|
# Note: this reusable workflow must called from a context that is triggered by a "Build and test" run (which then propagates the event)
|
||||||
|
# That context requires workflow_run, which runs in the context of the default branch,
|
||||||
|
# therefore we use the statuses api to place it on the source commit manually here
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: write
|
||||||
|
contents: read
|
||||||
|
statuses: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
trigger-rebuild-with-deps:
|
||||||
|
name: Apply required PRs from external repos
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event.workflow_run.conclusion == 'failure'
|
||||||
|
&& github.event.workflow_run.event == 'pull_request'
|
||||||
|
&& github.event.workflow_run.run_attempt == 1
|
||||||
|
steps:
|
||||||
|
- name: Look up PR url
|
||||||
|
id: lookup
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
PR_URL=$(gh api \
|
||||||
|
"repos/${{ github.repository }}/commits/${{ github.event.workflow_run.head_sha }}/pulls" \
|
||||||
|
--jq "[.[] | select(.head.sha == \"${{ github.event.workflow_run.head_sha }}\" and .state == \"open\")] | first | .html_url // empty")
|
||||||
|
|
||||||
|
if [ -z "$PR_URL" ]; then
|
||||||
|
echo "Failed to find a PR url"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "url=$PR_URL" >> "$GITHUB_OUTPUT"
|
||||||
|
|
||||||
|
- name: Collect required PRs
|
||||||
|
uses: MalTeeez/packscripts@a89fe398d047ac9e2e165465a51096be4f9853cb
|
||||||
|
env:
|
||||||
|
NO_COLOR: 1
|
||||||
|
with:
|
||||||
|
command: >-
|
||||||
|
pr deps ${{ steps.lookup.outputs.url }}
|
||||||
|
--target_dir ./.packscripts/
|
||||||
|
--jar_suffix -dev.jar
|
||||||
|
--artifact_name -dev.jar
|
||||||
|
--artifact_name build-libs
|
||||||
|
--build_job "Build and test"
|
||||||
|
--other_allowed_owner "GTNewHorizons"
|
||||||
|
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
config: https://raw.githubusercontent.com/MalTeeez/packscripts-auto-builds/refs/heads/gtnh-daily/packscripts.json
|
||||||
|
annotated_file: https://raw.githubusercontent.com/MalTeeez/packscripts-auto-builds/refs/heads/gtnh-daily/annotated_mods.json
|
||||||
|
|
||||||
|
- name: Check if deps were collected
|
||||||
|
id: check-deps
|
||||||
|
run: |
|
||||||
|
if [ -n "$(ls -A ./.packscripts/ 2>/dev/null)" ]; then
|
||||||
|
echo "found=true" >> "$GITHUB_OUTPUT"
|
||||||
|
else
|
||||||
|
echo "found=false" >> "$GITHUB_OUTPUT"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Mark status pending on PR commit
|
||||||
|
if: steps.check-deps.outputs.found == 'true'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh api -X POST \
|
||||||
|
repos/${{ github.repository }}/statuses/${{ github.event.workflow_run.head_sha }} \
|
||||||
|
-f state="pending" \
|
||||||
|
-f context="Trigger rebuild with deps" \
|
||||||
|
-f description="Applying external PR deps and rebuilding…" \
|
||||||
|
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
|
|
||||||
|
- name: Upload external deps artifact
|
||||||
|
if: steps.check-deps.outputs.found == 'true'
|
||||||
|
uses: actions/upload-artifact@v7
|
||||||
|
with:
|
||||||
|
# Named after the triggering run ID so the rerun can find it by its own run_id.
|
||||||
|
# workflow_run always runs in the default branch context, so artifacts would otherwise
|
||||||
|
# be filed under master's head_sha instead of the PR's, making them invisible to the rerun.
|
||||||
|
name: external-deps-${{ github.event.workflow_run.id }}
|
||||||
|
path: ./.packscripts/
|
||||||
|
include-hidden-files: true
|
||||||
|
|
||||||
|
- name: Rerun failed build
|
||||||
|
if: steps.check-deps.outputs.found == 'true'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh api -X POST \
|
||||||
|
repos/${{ github.repository }}/actions/runs/${{ github.event.workflow_run.id }}/rerun-failed-jobs
|
||||||
|
|
||||||
|
- name: Report final status to PR commit
|
||||||
|
if: always() && steps.check-deps.outputs.found == 'true'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh api -X POST \
|
||||||
|
repos/${{ github.repository }}/statuses/${{ github.event.workflow_run.head_sha }} \
|
||||||
|
-f state="${{ job.status }}" \
|
||||||
|
-f context="Trigger rebuild with deps" \
|
||||||
|
-f description="External PR deps applied; rebuild triggered" \
|
||||||
|
-f target_url="${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}"
|
||||||
119
scripts/server.sh
Normal file
119
scripts/server.sh
Normal file
@ -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
|
||||||
96
scripts/upload-deps-to-localmaven.sh
Normal file
96
scripts/upload-deps-to-localmaven.sh
Normal file
@ -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
|
||||||
87
scripts/verify_server.sh
Normal file
87
scripts/verify_server.sh
Normal file
@ -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"
|
||||||
@ -18,3 +18,4 @@ jobs:
|
|||||||
# horizonqa: true
|
# horizonqa: true
|
||||||
# horizonqa-tests: ''
|
# horizonqa-tests: ''
|
||||||
# horizonqa-allow-no-tests: false
|
# horizonqa-allow-no-tests: false
|
||||||
|
# external-deps-inclusion: true
|
||||||
|
|||||||
10
templates/gate-by-required.yml
Normal file
10
templates/gate-by-required.yml
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
name: Check state of other required PRs
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
branches: [ master, main, release/** ]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
check-required-prs:
|
||||||
|
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/gate-by-required.yml@master
|
||||||
|
secrets: inherit
|
||||||
19
templates/latest-daily-integration-test.yml
Normal file
19
templates/latest-daily-integration-test.yml
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
name: Test integration in latest daily
|
||||||
|
|
||||||
|
# Shim to forward the "Build and test" completion to the full pack test wf, whose
|
||||||
|
# jobs inherit this workflow_run event context (github.event.workflow_run.*)
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["Build and test"]
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
statuses: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
latest-daily-integration-test:
|
||||||
|
if: github.event.workflow_run.event == 'pull_request'
|
||||||
|
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/latest-daily-integration-test.yml@master
|
||||||
|
secrets: inherit
|
||||||
23
templates/trigger-rebuild-with-deps.yml
Normal file
23
templates/trigger-rebuild-with-deps.yml
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
name: Trigger a rebuild with externally required PRs
|
||||||
|
|
||||||
|
# Shim to forward the "Build and test" completion to the rebuild with deps wf, whose
|
||||||
|
# job inherits this workflow_run event context (github.event.workflow_run.*)
|
||||||
|
on:
|
||||||
|
workflow_run:
|
||||||
|
workflows: ["Build and test"]
|
||||||
|
types: [completed]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
actions: write
|
||||||
|
contents: read
|
||||||
|
statuses: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
trigger-rebuild-with-deps:
|
||||||
|
# Only act on a failed, first-attempt PR build
|
||||||
|
if: >-
|
||||||
|
github.event.workflow_run.conclusion == 'failure'
|
||||||
|
&& github.event.workflow_run.event == 'pull_request'
|
||||||
|
&& github.event.workflow_run.run_attempt == 1
|
||||||
|
uses: GTNewHorizons/GTNH-Actions-Workflows/.github/workflows/trigger-rebuild-with-deps.yml@master
|
||||||
|
secrets: inherit
|
||||||
Loading…
x
Reference in New Issue
Block a user