MetaEditor transfers compiled output to the Experts mirror of Shared Projects, so the hook's archive step never found an .ex5 next to the .mq5. Archive from the mirror instead, and also deploy each successful build to MQL5/Experts/VizionAI-Trading/profitgtx.ex5 so the EA shows up top-level in the MT5 Navigator for drag-and-drop. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
105 lines
4.6 KiB
Shell
105 lines
4.6 KiB
Shell
#!/bin/sh
|
|
# Auto-version, compile, and prune EA releases. Fires after every commit on main.
|
|
# Pattern: sequential build-NNNN git tags + matching archived .ex5 builds,
|
|
# capped at MAX_KEEP by deleting the oldest ones each time the cap is exceeded.
|
|
|
|
REPO_ROOT="$(git rev-parse --show-toplevel)"
|
|
cd "$REPO_ROOT" || exit 0
|
|
|
|
BRANCH="$(git rev-parse --abbrev-ref HEAD)"
|
|
[ "$BRANCH" = "main" ] || exit 0
|
|
|
|
MAX_KEEP=10
|
|
MQ5_FILE="$REPO_ROOT/profitgtx.mq5"
|
|
BUILD_DIR="$REPO_ROOT/builds"
|
|
METAEDITOR="/c/Program Files/MetaTrader 5 Terminal/MetaEditor64.exe"
|
|
|
|
# MetaEditor writes the compiled .ex5 to the Experts mirror of the Shared
|
|
# Projects tree, not next to the .mq5 — archive/deploy from there.
|
|
EX5_MIRROR="$(printf '%s' "$REPO_ROOT" | sed 's|/MQL5/Shared Projects/|/MQL5/Experts/Shared Projects/|')/profitgtx.ex5"
|
|
MQL5_DIR="$(printf '%s' "$REPO_ROOT" | sed 's|\(/MQL5\)/Shared Projects/.*|\1|')"
|
|
# Navigator-friendly copy so the EA can be drag-and-dropped from
|
|
# Expert Advisors -> VizionAI-Trading without digging through Shared Projects.
|
|
DEPLOY_DIR="$MQL5_DIR/Experts/VizionAI-Trading"
|
|
|
|
mkdir -p "$BUILD_DIR" "$DEPLOY_DIR"
|
|
|
|
# 1. Next sequential build number, derived from existing tags (no state file needed)
|
|
LAST=$(git tag -l "build-*" | sed 's/^build-//' | sort -n | tail -1)
|
|
[ -z "$LAST" ] && LAST=0
|
|
NEXT=$((10#$LAST + 1))
|
|
TAG=$(printf "build-%04d" "$NEXT")
|
|
|
|
# 2. Tag this commit
|
|
git tag -a "$TAG" -m "Automated build $TAG" || exit 0
|
|
|
|
# 3. Compile via MetaEditor CLI and archive the .ex5 on success
|
|
# MetaEditor64.exe hands /compile off to an already-running GUI instance
|
|
# and returns immediately without actually compiling or writing a log, so
|
|
# skip the compile step entirely when an instance is already open rather
|
|
# than race a compile that will never happen. When no instance is open,
|
|
# it runs headless and blocks, but poll anyway as a safety margin.
|
|
LOG_FILE="$BUILD_DIR/$TAG.log"
|
|
rm -f "$LOG_FILE"
|
|
if tasklist //FI "IMAGENAME eq MetaEditor64.exe" 2>/dev/null | grep -qi metaeditor64; then
|
|
echo "[post-commit] MetaEditor is already open — skipping compile for $TAG (close it to get an auto-compiled build next commit)"
|
|
elif [ -f "$MQ5_FILE" ] && [ -x "$METAEDITOR" ]; then
|
|
"$METAEDITOR" /compile:"$MQ5_FILE" /log:"$LOG_FILE" >/dev/null 2>&1
|
|
|
|
TRIES=0
|
|
LAST_SIZE=-1
|
|
while [ "$TRIES" -lt 30 ]; do
|
|
sleep 1
|
|
TRIES=$((TRIES + 1))
|
|
[ -f "$LOG_FILE" ] || continue
|
|
CUR_SIZE=$(wc -c < "$LOG_FILE" 2>/dev/null || echo 0)
|
|
[ "$CUR_SIZE" = "$LAST_SIZE" ] && [ "$CUR_SIZE" -gt 0 ] && break
|
|
LAST_SIZE=$CUR_SIZE
|
|
done
|
|
|
|
LOG_TEXT=$(iconv -f UTF-16LE -t UTF-8 "$LOG_FILE" 2>/dev/null || cat "$LOG_FILE" 2>/dev/null)
|
|
if echo "$LOG_TEXT" | grep -qi "0 error"; then
|
|
# Prefer the Experts mirror (where the compiler transfers output);
|
|
# fall back to a local .ex5 for setups that compile in place.
|
|
EX5_SRC="$EX5_MIRROR"
|
|
[ -f "$EX5_SRC" ] || EX5_SRC="${MQ5_FILE%.mq5}.ex5"
|
|
if [ -f "$EX5_SRC" ]; then
|
|
cp "$EX5_SRC" "$BUILD_DIR/profitgtx_$TAG.ex5"
|
|
cp "$EX5_SRC" "$DEPLOY_DIR/profitgtx.ex5"
|
|
echo "[post-commit] Built, archived, and deployed $TAG (Navigator: Expert Advisors > VizionAI-Trading)"
|
|
else
|
|
echo "[post-commit] WARNING: compile succeeded but no .ex5 found to archive"
|
|
fi
|
|
else
|
|
echo "[post-commit] WARNING: compile for $TAG reported errors, see $LOG_FILE"
|
|
fi
|
|
fi
|
|
|
|
# 4. Push commit + tag
|
|
git push origin main "$TAG" >/dev/null 2>&1 || echo "[post-commit] WARNING: push failed, tag/build kept locally"
|
|
|
|
# 5. Prune tags beyond MAX_KEEP (oldest first, local + remote)
|
|
TAG_NUMS=$(git tag -l "build-*" | sed 's/^build-//' | sort -n)
|
|
TAG_COUNT=$(printf '%s\n' "$TAG_NUMS" | grep -c .)
|
|
if [ "$TAG_COUNT" -gt "$MAX_KEEP" ]; then
|
|
EXCESS=$((TAG_COUNT - MAX_KEEP))
|
|
printf '%s\n' "$TAG_NUMS" | head -n "$EXCESS" | while read -r n; do
|
|
OLDTAG="build-$(printf '%04d' "$n")"
|
|
git tag -d "$OLDTAG" >/dev/null 2>&1
|
|
git push origin ":refs/tags/$OLDTAG" >/dev/null 2>&1
|
|
echo "[post-commit] Pruned tag $OLDTAG"
|
|
done
|
|
fi
|
|
|
|
# 6. Prune archived .ex5 builds beyond MAX_KEEP (oldest first)
|
|
BUILD_NUMS=$(ls "$BUILD_DIR" 2>/dev/null | grep -E '^profitgtx_build-[0-9]{4}\.ex5$' | sed -E 's/^profitgtx_build-([0-9]{4})\.ex5$/\1/' | sort -n)
|
|
BUILD_COUNT=$(printf '%s\n' "$BUILD_NUMS" | grep -c .)
|
|
if [ "$BUILD_COUNT" -gt "$MAX_KEEP" ]; then
|
|
BEXCESS=$((BUILD_COUNT - MAX_KEEP))
|
|
printf '%s\n' "$BUILD_NUMS" | head -n "$BEXCESS" | while read -r n; do
|
|
rm -f "$BUILD_DIR/profitgtx_build-$n.ex5" "$BUILD_DIR/build-$n.log"
|
|
echo "[post-commit] Pruned build artifact build-$n"
|
|
done
|
|
fi
|
|
|
|
exit 0
|