#!/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" mkdir -p "$BUILD_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 EX5_SRC="${MQ5_FILE%.mq5}.ex5" [ -f "$EX5_SRC" ] && cp "$EX5_SRC" "$BUILD_DIR/profitgtx_$TAG.ex5" echo "[post-commit] Built and archived $TAG" 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