fix(multicall): resolve critical multicall parsing corruption issues
- Added comprehensive bounds checking to prevent buffer overruns in multicall parsing - Implemented graduated validation system (Strict/Moderate/Permissive) to reduce false positives - Added LRU caching system for address validation with 10-minute TTL - Enhanced ABI decoder with missing Universal Router and Arbitrum-specific DEX signatures - Fixed duplicate function declarations and import conflicts across multiple files - Added error recovery mechanisms with multiple fallback strategies - Updated tests to handle new validation behavior for suspicious addresses - Fixed parser test expectations for improved validation system - Applied gofmt formatting fixes to ensure code style compliance - Fixed mutex copying issues in monitoring package by introducing MetricsSnapshot - Resolved critical security vulnerabilities in heuristic address extraction - Progress: Updated TODO audit from 10% to 35% complete 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
110
scripts/build.sh
110
scripts/build.sh
@@ -1,21 +1,101 @@
|
||||
#!/bin/bash
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# build.sh - Build the MEV bot
|
||||
# Reusable, agnostic build script
|
||||
# Can be used in any Go project by adjusting configuration
|
||||
|
||||
echo "Building MEV bot..."
|
||||
# Configuration variables
|
||||
BINARY_NAME="${BINARY_NAME:-$(basename $(pwd))}"
|
||||
BINARY_DIR="${BINARY_DIR:-bin}"
|
||||
MAIN_FILE="${MAIN_FILE:-cmd/mev-bot/main.go}"
|
||||
BUILD_TAGS="${BUILD_TAGS:-}"
|
||||
LDFLAGS="${LDFLAGS:-}"
|
||||
OUTPUT="${OUTPUT:-$BINARY_DIR/$BINARY_NAME}"
|
||||
GOOS="${GOOS:-$(go env GOOS)}"
|
||||
GOARCH="${GOARCH:-$(go env GOARCH)}"
|
||||
|
||||
# Create bin directory if it doesn't exist
|
||||
mkdir -p bin
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-n|--name)
|
||||
BINARY_NAME="$2"
|
||||
shift 2
|
||||
;;
|
||||
-o|--output)
|
||||
OUTPUT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-m|--main)
|
||||
MAIN_FILE="$2"
|
||||
shift 2
|
||||
;;
|
||||
-t|--tags)
|
||||
BUILD_TAGS="$2"
|
||||
shift 2
|
||||
;;
|
||||
-l|--ldflags)
|
||||
LDFLAGS="$2"
|
||||
shift 2
|
||||
;;
|
||||
--goos)
|
||||
GOOS="$2"
|
||||
shift 2
|
||||
;;
|
||||
--goarch)
|
||||
GOARCH="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo "Build a Go application with configurable options"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -n, --name NAME Binary name (default: current directory name)"
|
||||
echo " -o, --output PATH Output path (default: bin/BINARY_NAME)"
|
||||
echo " -m, --main PATH Main package path (default: .)"
|
||||
echo " -t, --tags TAGS Build tags"
|
||||
echo " -l, --ldflags FLAGS Ldflags to pass to go build"
|
||||
echo " --goos OS Target OS (default: $(go env GOOS))"
|
||||
echo " --goarch ARCH Target architecture (default: $(go env GOARCH))"
|
||||
echo " -h, --help Show this help"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Building $BINARY_NAME for $GOOS/$GOARCH..."
|
||||
|
||||
# Ensure local Go cache directories exist when not provided
|
||||
PROJECT_ROOT="$(pwd)"
|
||||
if [[ -z "${GOCACHE:-}" ]]; then
|
||||
export GOCACHE="${PROJECT_ROOT}/.gocache"
|
||||
fi
|
||||
if [[ -z "${GOMODCACHE:-}" ]]; then
|
||||
export GOMODCACHE="${PROJECT_ROOT}/.gomodcache"
|
||||
fi
|
||||
if [[ -z "${GOPATH:-}" ]]; then
|
||||
export GOPATH="${PROJECT_ROOT}/.gopath"
|
||||
fi
|
||||
if [[ -z "${GOFLAGS:-}" && -d "${PROJECT_ROOT}/vendor" ]]; then
|
||||
export GOFLAGS="-mod=vendor"
|
||||
fi
|
||||
|
||||
mkdir -p "$GOCACHE" "$GOMODCACHE" "${GOPATH}/pkg/mod"
|
||||
|
||||
# Create binary directory
|
||||
mkdir -p "$(dirname "$OUTPUT")"
|
||||
|
||||
# Set environment variables for cross-compilation
|
||||
export GOOS="$GOOS"
|
||||
export GOARCH="$GOARCH"
|
||||
|
||||
# Build the application
|
||||
echo "go build -o $OUTPUT $BUILD_TAGS:+-tags $BUILD_TAGS $LDFLAGS:+-ldflags $LDFLAGS $MAIN_FILE"
|
||||
go build -o "$OUTPUT" ${BUILD_TAGS:+-tags "$BUILD_TAGS"} ${LDFLAGS:+-ldflags "$LDFLAGS"} "$MAIN_FILE"
|
||||
|
||||
goimports -w .
|
||||
go mod tidy && go mod vendor
|
||||
go build -o bin/mev-bot cmd/mev-bot/main.go
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
echo "Build successful! Binary created at bin/mev-bot"
|
||||
else
|
||||
echo "Build failed!"
|
||||
exit 1
|
||||
fi
|
||||
echo "Build completed successfully!"
|
||||
echo "Binary: $OUTPUT"
|
||||
|
||||
66
scripts/ci-container.sh
Executable file
66
scripts/ci-container.sh
Executable file
@@ -0,0 +1,66 @@
|
||||
#!/usr/bin/env bash
|
||||
# Run CI pipeline inside a container (for isolation)
|
||||
# Usage: ./scripts/ci-container.sh [quick|dev|full]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
MODE="${1:-dev}"
|
||||
|
||||
case $MODE in
|
||||
quick)
|
||||
echo "🐳 Running Quick CI in Container..."
|
||||
SKIP_FLAGS="-e HARNESS_SKIP_DOCKER=true -e HARNESS_SKIP_MATH_AUDIT=true -e HARNESS_SKIP_SECURITY=true"
|
||||
;;
|
||||
dev)
|
||||
echo "🐳 Running Development CI in Container..."
|
||||
SKIP_FLAGS="-e HARNESS_SKIP_DOCKER=true"
|
||||
;;
|
||||
full)
|
||||
echo "🐳 Running Full CI in Container (no Docker build)..."
|
||||
SKIP_FLAGS="-e HARNESS_SKIP_DOCKER=true"
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [quick|dev|full]"
|
||||
echo " quick - Fast validation (30-60s)"
|
||||
echo " dev - Development pipeline (1-2min)"
|
||||
echo " full - Complete validation except Docker (2-3min)"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check for container runtime
|
||||
if command -v podman >/dev/null 2>&1; then
|
||||
RUNTIME="podman"
|
||||
elif command -v docker >/dev/null 2>&1; then
|
||||
RUNTIME="docker"
|
||||
else
|
||||
echo "❌ Error: Neither podman nor docker found"
|
||||
echo "Install with: sudo apt install podman"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Using container runtime: $RUNTIME"
|
||||
echo ""
|
||||
|
||||
# Create cache directories for performance
|
||||
mkdir -p .gocache .gomodcache
|
||||
|
||||
# Run pipeline in container
|
||||
$RUNTIME run --rm \
|
||||
-v "$(pwd)":/workspace \
|
||||
-v "$(pwd)/.gocache":/root/.cache/go-build \
|
||||
-v "$(pwd)/.gomodcache":/go/pkg/mod \
|
||||
-w /workspace \
|
||||
$SKIP_FLAGS \
|
||||
golang:1.25-alpine \
|
||||
sh -c "
|
||||
echo 'Installing CI tools...' &&
|
||||
apk add --no-cache git make bash curl &&
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest &&
|
||||
echo 'Running pipeline...' &&
|
||||
./harness/local-ci-pipeline.sh
|
||||
"
|
||||
|
||||
echo ""
|
||||
echo "✅ Container CI completed successfully!"
|
||||
echo "📊 Check reports in: harness/reports/"
|
||||
17
scripts/ci-dev.sh
Executable file
17
scripts/ci-dev.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
# Development CI pipeline - good balance of speed and coverage
|
||||
# Usage: ./scripts/ci-dev.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "🛠️ Running Development CI Pipeline..."
|
||||
echo "⏱️ Expected time: 1-2 minutes"
|
||||
echo ""
|
||||
|
||||
HARNESS_SKIP_DOCKER=true \
|
||||
./harness/local-ci-pipeline.sh
|
||||
|
||||
echo ""
|
||||
echo "✅ Development CI completed successfully!"
|
||||
echo "📊 Check reports in: harness/reports/"
|
||||
echo "📋 For full validation, run: ./scripts/ci-full.sh"
|
||||
16
scripts/ci-full.sh
Executable file
16
scripts/ci-full.sh
Executable file
@@ -0,0 +1,16 @@
|
||||
#!/usr/bin/env bash
|
||||
# Full CI pipeline - complete validation for releases
|
||||
# Usage: ./scripts/ci-full.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "🎯 Running Full CI Pipeline..."
|
||||
echo "⏱️ Expected time: 3-5 minutes"
|
||||
echo ""
|
||||
|
||||
./harness/local-ci-pipeline.sh
|
||||
|
||||
echo ""
|
||||
echo "🎉 Full CI completed successfully!"
|
||||
echo "📊 Complete reports available in: harness/reports/"
|
||||
echo "📋 View summary: cat harness/reports/pipeline-report.md"
|
||||
33
scripts/ci-precommit.sh
Executable file
33
scripts/ci-precommit.sh
Executable file
@@ -0,0 +1,33 @@
|
||||
#!/usr/bin/env bash
|
||||
# Pre-commit validation - minimal checks for speed
|
||||
# Usage: ./scripts/ci-precommit.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "🔍 Running Pre-commit Validation..."
|
||||
echo "⏱️ Expected time: 10-30 seconds"
|
||||
echo ""
|
||||
|
||||
# Quick build and test
|
||||
echo "Building binary..."
|
||||
make build
|
||||
|
||||
echo "Running tests..."
|
||||
make test
|
||||
|
||||
echo "Checking formatting..."
|
||||
if ! gofmt -l . | grep -q .; then
|
||||
echo "✅ Code formatting is clean"
|
||||
else
|
||||
echo "❌ Code needs formatting:"
|
||||
gofmt -l .
|
||||
echo "Run: gofmt -w ."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Running static analysis..."
|
||||
go vet ./...
|
||||
|
||||
echo ""
|
||||
echo "✅ Pre-commit validation passed!"
|
||||
echo "💡 For more thorough checks, run: ./scripts/ci-quick.sh"
|
||||
18
scripts/ci-quick.sh
Executable file
18
scripts/ci-quick.sh
Executable file
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/env bash
|
||||
# Quick CI validation for development workflow
|
||||
# Usage: ./scripts/ci-quick.sh
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
echo "🚀 Running Quick CI Pipeline..."
|
||||
echo "⏱️ Expected time: 30-60 seconds"
|
||||
echo ""
|
||||
|
||||
HARNESS_SKIP_DOCKER=true \
|
||||
HARNESS_SKIP_MATH_AUDIT=true \
|
||||
HARNESS_SKIP_SECURITY=true \
|
||||
./harness/local-ci-pipeline.sh
|
||||
|
||||
echo ""
|
||||
echo "✅ Quick CI completed successfully!"
|
||||
echo "📋 For full validation, run: ./scripts/ci-full.sh"
|
||||
59
scripts/ci-watch.sh
Executable file
59
scripts/ci-watch.sh
Executable file
@@ -0,0 +1,59 @@
|
||||
#!/usr/bin/env bash
|
||||
# Watch for file changes and run CI automatically
|
||||
# Usage: ./scripts/ci-watch.sh [quick|precommit]
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
MODE="${1:-precommit}"
|
||||
|
||||
case $MODE in
|
||||
quick)
|
||||
CI_SCRIPT="./scripts/ci-quick.sh"
|
||||
echo "👀 Watching for changes - will run quick CI..."
|
||||
;;
|
||||
precommit)
|
||||
CI_SCRIPT="./scripts/ci-precommit.sh"
|
||||
echo "👀 Watching for changes - will run pre-commit validation..."
|
||||
;;
|
||||
*)
|
||||
echo "Usage: $0 [quick|precommit]"
|
||||
echo " precommit - Fast build/test only"
|
||||
echo " quick - Quick CI pipeline"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Check if inotifywait is available
|
||||
if ! command -v inotifywait >/dev/null 2>&1; then
|
||||
echo "❌ inotifywait not found. Install with:"
|
||||
echo "sudo apt install inotify-tools"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Watching: pkg/ internal/ cmd/ *.go"
|
||||
echo "Press Ctrl+C to stop"
|
||||
echo ""
|
||||
|
||||
# Run initial check
|
||||
$CI_SCRIPT
|
||||
|
||||
echo ""
|
||||
echo "👀 Watching for changes..."
|
||||
|
||||
# Watch for changes and re-run
|
||||
while inotifywait -q -r -e modify,move,create,delete \
|
||||
--include='.*\.go$' \
|
||||
pkg/ internal/ cmd/ . 2>/dev/null; do
|
||||
|
||||
echo ""
|
||||
echo "🔄 Files changed, running $MODE validation..."
|
||||
echo ""
|
||||
|
||||
if $CI_SCRIPT; then
|
||||
echo ""
|
||||
echo "✅ Validation passed - watching for changes..."
|
||||
else
|
||||
echo ""
|
||||
echo "❌ Validation failed - fix issues and save files to retry"
|
||||
fi
|
||||
done
|
||||
495
scripts/create-project-template.sh
Executable file
495
scripts/create-project-template.sh
Executable file
@@ -0,0 +1,495 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Universal Go Project Template
|
||||
# This template can be used to quickly set up a new Go project with standardized structure and tooling
|
||||
|
||||
PROJECT_NAME="${1:-}"
|
||||
if [ -z "$PROJECT_NAME" ]; then
|
||||
echo "Usage: $0 <project-name>"
|
||||
echo "Creates a new Go project template with standardized structure and tooling"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating new Go project: $PROJECT_NAME"
|
||||
|
||||
# Create project directory structure
|
||||
mkdir -p "$PROJECT_NAME"/{cmd,pkg,scripts,docs,tests,examples,tools,config,logs,reports,storage}
|
||||
|
||||
# Create main.go in cmd directory
|
||||
cat > "$PROJECT_NAME/cmd/main.go" << EOF
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
)
|
||||
|
||||
func main() {
|
||||
fmt.Println("Hello, $PROJECT_NAME!")
|
||||
log.Println("Starting $PROJECT_NAME application...")
|
||||
|
||||
// Your application logic here
|
||||
|
||||
log.Println("Application finished.")
|
||||
}
|
||||
EOF
|
||||
|
||||
# Create README
|
||||
cat > "$PROJECT_NAME/README.md" << EOF
|
||||
# $PROJECT_NAME
|
||||
|
||||
A Go project with standardized structure and tooling.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- \`cmd/\` - Main applications
|
||||
- \`pkg/\` - Library code
|
||||
- \`scripts/\` - Build and deployment scripts
|
||||
- \`tests/\` - Test files (unit, integration, e2e)
|
||||
- \`docs/\` - Documentation
|
||||
- \`examples/\` - Example code
|
||||
- \`tools/\` - Development tools
|
||||
- \`config/\` - Configuration files
|
||||
|
||||
## Getting Started
|
||||
|
||||
1. Install dependencies: \`make deps\`
|
||||
2. Run tests: \`make test\`
|
||||
3. Build: \`make build\`
|
||||
4. Run: \`make run\`
|
||||
|
||||
## Development Commands
|
||||
|
||||
\`\`\`
|
||||
make build # Build the application
|
||||
make test # Run tests
|
||||
make test-coverage # Run tests with coverage
|
||||
make lint # Lint the code
|
||||
make fmt # Format the code
|
||||
make vet # Vet the code
|
||||
make run # Build and run the application
|
||||
make dev-setup # Setup development environment
|
||||
make audit-full # Run comprehensive audit
|
||||
\`\`\`
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
EOF
|
||||
|
||||
# Create go.mod
|
||||
cat > "$PROJECT_NAME/go.mod" << EOF
|
||||
module $PROJECT_NAME
|
||||
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
)
|
||||
EOF
|
||||
|
||||
# Create comprehensive Makefile
|
||||
cat > "$PROJECT_NAME/Makefile" << 'MAKEFILE'
|
||||
# Universal Go Project Makefile Template
|
||||
|
||||
# Variables
|
||||
BINARY=$(notdir $(CURDIR))
|
||||
BINARY_PATH=bin/$(BINARY)
|
||||
MAIN_FILE=cmd/main.go
|
||||
|
||||
# Default target
|
||||
.PHONY: all
|
||||
all: build
|
||||
|
||||
# Build the application
|
||||
.PHONY: build
|
||||
build:
|
||||
@echo "Building $(BINARY)..."
|
||||
@mkdir -p bin
|
||||
@go build -o $(BINARY_PATH) $(MAIN_FILE)
|
||||
@echo "Build successful!"
|
||||
|
||||
# Build with race detection
|
||||
.PHONY: build-race
|
||||
build-race:
|
||||
@echo "Building $(BINARY) with race detection..."
|
||||
@mkdir -p bin
|
||||
@go build -race -o $(BINARY_PATH) $(MAIN_FILE)
|
||||
@echo "Race-build successful!"
|
||||
|
||||
# Run the application
|
||||
.PHONY: run
|
||||
run: build
|
||||
@echo "Running $(BINARY)..."
|
||||
@$(BINARY_PATH)
|
||||
|
||||
# Run the application in development mode
|
||||
.PHONY: run-dev
|
||||
run-dev:
|
||||
@echo "Running $(BINARY) in development mode..."
|
||||
@go run $(MAIN_FILE)
|
||||
|
||||
# Multi-level Testing System
|
||||
# Basic tests (fast)
|
||||
.PHONY: test-basic
|
||||
test-basic:
|
||||
@echo "Running basic tests (fast)..."
|
||||
@go test -v -short ./...
|
||||
|
||||
# Unit tests
|
||||
.PHONY: test-unit
|
||||
test-unit:
|
||||
@echo "Running unit tests..."
|
||||
@go test -v ./tests/unit/... ./pkg/...
|
||||
|
||||
# Integration tests
|
||||
.PHONY: test-integration
|
||||
test-integration:
|
||||
@echo "Running integration tests..."
|
||||
@go test -v ./tests/integration/...
|
||||
|
||||
# End-to-end tests
|
||||
.PHONY: test-e2e
|
||||
test-e2e:
|
||||
@echo "Running end-to-end tests..."
|
||||
@go test -v ./tests/e2e/...
|
||||
|
||||
# Property tests
|
||||
.PHONY: test-property
|
||||
test-property:
|
||||
@echo "Running property tests..."
|
||||
@go test -v ./tests/property/...
|
||||
|
||||
# Fuzzing tests
|
||||
.PHONY: test-fuzzing
|
||||
test-fuzzing:
|
||||
@echo "Running fuzzing tests..."
|
||||
@go test -v ./tests/fuzzing/...
|
||||
|
||||
# Stress tests
|
||||
.PHONY: test-stress
|
||||
test-stress:
|
||||
@echo "Running stress tests..."
|
||||
@go test -v ./tests/stress/...
|
||||
|
||||
# Security tests
|
||||
.PHONY: test-security
|
||||
test-security:
|
||||
@echo "Running security tests..."
|
||||
@go test -v ./tests/security/...
|
||||
|
||||
# Benchmark tests
|
||||
.PHONY: test-bench
|
||||
test-bench:
|
||||
@echo "Running benchmark tests..."
|
||||
@go test -bench=. -benchmem -run=^$$ ./...
|
||||
|
||||
# Comprehensive tests (all test types)
|
||||
.PHONY: test-comprehensive
|
||||
test-comprehensive:
|
||||
@echo "Running comprehensive tests..."
|
||||
@$(MAKE) test-unit
|
||||
@$(MAKE) test-integration
|
||||
@$(MAKE) test-e2e
|
||||
|
||||
# Full audit tests (comprehensive + security + stress + benchmarks)
|
||||
.PHONY: test-audit
|
||||
test-audit:
|
||||
@echo "Running full audit tests..."
|
||||
@$(MAKE) test-comprehensive
|
||||
@$(MAKE) test-security
|
||||
@$(MAKE) test-stress
|
||||
@$(MAKE) test-bench
|
||||
|
||||
# Run tests with coverage
|
||||
.PHONY: test-coverage
|
||||
test-coverage:
|
||||
@echo "Running tests with coverage..."
|
||||
@go test -coverprofile=coverage.out ./...
|
||||
@go tool cover -html=coverage.out -o coverage.html
|
||||
@echo "Coverage report generated: coverage.html"
|
||||
|
||||
# Run tests with coverage for specific package
|
||||
.PHONY: test-coverage-pkg
|
||||
test-coverage-pkg:
|
||||
@echo "Running tests with coverage for specific package..."
|
||||
@go test -coverprofile=coverage.out $(PKG) && go tool cover -html=coverage.out -o coverage.html
|
||||
@echo "Coverage report generated: coverage.html"
|
||||
|
||||
# Code Quality Tools
|
||||
# Format code
|
||||
.PHONY: fmt
|
||||
fmt:
|
||||
@echo "Formatting code..."
|
||||
@go fmt ./...
|
||||
|
||||
# Vet code
|
||||
.PHONY: vet
|
||||
vet:
|
||||
@echo "Vetting code..."
|
||||
@go vet ./...
|
||||
|
||||
# Lint code (requires golangci-lint)
|
||||
.PHONY: lint
|
||||
lint:
|
||||
@echo "Linting code..."
|
||||
@which golangci-lint > /dev/null || (echo "golangci-lint not found, installing..." && go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest)
|
||||
@golangci-lint run
|
||||
|
||||
# Security audit
|
||||
.PHONY: audit-security
|
||||
audit-security:
|
||||
@echo "Running security audit..."
|
||||
@which gosec > /dev/null || (echo "gosec not found, installing..." && go install github.com/securego/gosec/v2/cmd/gosec@latest)
|
||||
@gosec ./...
|
||||
@which govulncheck > /dev/null || (echo "govulncheck not found, installing..." && go install golang.org/x/vuln/cmd/govulncheck@latest)
|
||||
@govulncheck ./...
|
||||
|
||||
# Dependency audit
|
||||
.PHONY: audit-deps
|
||||
audit-deps:
|
||||
@echo "Running dependency audit..."
|
||||
@go list -m -u all
|
||||
@govulncheck ./...
|
||||
|
||||
# Code quality audit
|
||||
.PHONY: audit-quality
|
||||
audit-quality:
|
||||
@echo "Running code quality audit..."
|
||||
@$(MAKE) vet
|
||||
@$(MAKE) lint
|
||||
|
||||
# Comprehensive audit (all checks)
|
||||
.PHONY: audit-full
|
||||
audit-full:
|
||||
@echo "Running comprehensive audit..."
|
||||
@$(MAKE) audit-quality
|
||||
@$(MAKE) audit-security
|
||||
@$(MAKE) audit-deps
|
||||
@$(MAKE) test-audit
|
||||
|
||||
# Development helpers
|
||||
# Install dependencies
|
||||
.PHONY: deps
|
||||
deps:
|
||||
@echo "Installing dependencies..."
|
||||
@go mod tidy
|
||||
|
||||
# Install development dependencies
|
||||
.PHONY: dev-deps
|
||||
dev-deps:
|
||||
@echo "Installing development dependencies..."
|
||||
@go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
@go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
@go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
@go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
@go mod tidy
|
||||
@echo "Development dependencies installed!"
|
||||
|
||||
# Development setup
|
||||
.PHONY: dev-setup
|
||||
dev-setup:
|
||||
@echo "Setting up development environment..."
|
||||
@$(MAKE) deps
|
||||
@$(MAKE) dev-deps
|
||||
@./scripts/setup-dev.sh
|
||||
@echo "Development environment setup complete!"
|
||||
|
||||
# Development workflow (fmt + vet + lint + basic test)
|
||||
.PHONY: dev-workflow
|
||||
dev-workflow:
|
||||
@echo "Running development workflow..."
|
||||
@$(MAKE) fmt
|
||||
@$(MAKE) vet
|
||||
@$(MAKE) lint
|
||||
@$(MAKE) test-basic
|
||||
|
||||
# Development workflow with coverage
|
||||
.PHONY: dev-workflow-full
|
||||
dev-workflow-full:
|
||||
@echo "Running development workflow with coverage..."
|
||||
@$(MAKE) fmt
|
||||
@$(MAKE) vet
|
||||
@$(MAKE) lint
|
||||
@$(MAKE) test-coverage
|
||||
|
||||
# Debug run
|
||||
.PHONY: debug
|
||||
debug:
|
||||
@echo "Running application in debug mode..."
|
||||
@which dlv > /dev/null || (echo "delve not found, install with: go install github.com/go-delve/delve/cmd/dlv@latest && make dev-deps")
|
||||
@dlv exec -- $(BINARY_PATH)
|
||||
|
||||
# Watch and run tests (requires 'entr' command)
|
||||
.PHONY: watch-tests
|
||||
watch-tests:
|
||||
@echo "Watching for file changes and running tests..."
|
||||
@echo "Note: Requires 'entr' to be installed. Install with: apt-get install entr (or brew install entr)"
|
||||
@find . -name "*.go" -not -path "./vendor/*" -not -path "./bin/*" | entr -c $(MAKE) test-basic
|
||||
|
||||
# Watch and run dev workflow (requires 'entr' command)
|
||||
.PHONY: watch-dev
|
||||
watch-dev:
|
||||
@echo "Watching for file changes and running dev workflow..."
|
||||
@echo "Note: Requires 'entr' to be installed. Install with: apt-get install entr (or brew install entr)"
|
||||
@find . -name "*.go" -not -path "./vendor/*" -not -path "./bin/*" | entr -c $(MAKE) dev-workflow
|
||||
|
||||
# Documentation generation
|
||||
.PHONY: docs
|
||||
docs:
|
||||
@echo "Generating code documentation..."
|
||||
@mkdir -p docs/gen
|
||||
@go doc -all ./... > docs/gen/code-documentation.txt
|
||||
@echo "Code documentation generated in docs/gen/code-documentation.txt"
|
||||
|
||||
# Clean build artifacts
|
||||
.PHONY: clean
|
||||
clean:
|
||||
@echo "Cleaning..."
|
||||
@rm -rf bin/
|
||||
@rm -f coverage.out coverage.html
|
||||
@rm -rf reports/
|
||||
@echo "Clean complete!"
|
||||
|
||||
# Update dependencies
|
||||
.PHONY: update
|
||||
update:
|
||||
@echo "Updating dependencies..."
|
||||
@go get -u ./...
|
||||
@go mod tidy
|
||||
@echo "Dependencies updated!"
|
||||
|
||||
# Help
|
||||
.PHONY: help
|
||||
help:
|
||||
@echo "Available targets:"
|
||||
@echo ""
|
||||
@echo "Build & Run:"
|
||||
@echo " all - Build the application (default)"
|
||||
@echo " build - Build the application"
|
||||
@echo " build-race - Build with race detection"
|
||||
@echo " run - Build and run the application"
|
||||
@echo " run-dev - Run without building"
|
||||
@echo ""
|
||||
@echo "Testing (Multi-Level):"
|
||||
@echo " test-basic - Run basic tests (fast)"
|
||||
@echo " test-unit - Run unit tests"
|
||||
@echo " test-integration - Run integration tests"
|
||||
@echo " test-e2e - Run end-to-end tests"
|
||||
@echo " test-property - Run property tests"
|
||||
@echo " test-fuzzing - Run fuzzing tests"
|
||||
@echo " test-stress - Run stress tests"
|
||||
@echo " test-security - Run security tests"
|
||||
@echo " test-bench - Run benchmark tests"
|
||||
@echo " test-comprehensive - Run comprehensive tests (all test types)"
|
||||
@echo " test-audit - Run full audit tests (comprehensive + security + stress)"
|
||||
@echo " test-coverage - Run tests with coverage report"
|
||||
@echo " test-coverage-pkg - Run tests with coverage for specific package (use with PKG=package/path)"
|
||||
@echo ""
|
||||
@echo "Quality & Auditing:"
|
||||
@echo " fmt - Format code"
|
||||
@echo " vet - Vet code"
|
||||
@echo " lint - Lint code (requires golangci-lint)"
|
||||
@echo " audit-security - Run security audit"
|
||||
@echo " audit-deps - Run dependency audit"
|
||||
@echo " audit-quality - Run code quality audit"
|
||||
@echo " audit-full - Run comprehensive audit (all checks)"
|
||||
@echo ""
|
||||
@echo "Development:"
|
||||
@echo " dev-setup - Setup development environment"
|
||||
@echo " dev-deps - Install development dependencies"
|
||||
@echo " dev-workflow - Run development workflow (fmt + vet + lint + basic test)"
|
||||
@echo " dev-workflow-full - Run development workflow with coverage"
|
||||
@echo " debug - Run application in debug mode"
|
||||
@echo " watch-tests - Watch for changes and run basic tests (requires entr)"
|
||||
@echo " watch-dev - Watch for changes and run dev workflow (requires entr)"
|
||||
@echo ""
|
||||
@echo "Maintenance:"
|
||||
@echo " clean - Clean build artifacts"
|
||||
@echo " deps - Install dependencies"
|
||||
@echo " update - Update dependencies"
|
||||
@echo " docs - Generate code documentation"
|
||||
@echo " help - Show this help"
|
||||
@echo ""
|
||||
@echo "Examples:"
|
||||
@echo " make test-coverage PKG=./pkg/my-package/ # Coverage for specific package"
|
||||
@echo " make watch-dev # Watch for changes and run dev workflow"
|
||||
</PROMPT>
|
||||
|
||||
# Create setup script
|
||||
cat > "$PROJECT_NAME/scripts/setup-dev.sh" << 'SETUP'
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Development environment setup script
|
||||
|
||||
echo "Setting up development environment for $(basename $(pwd))..."
|
||||
|
||||
# Create directories if they don't exist
|
||||
mkdir -p logs
|
||||
mkdir -p reports
|
||||
mkdir -p reports/coverage
|
||||
mkdir -p reports/test-results
|
||||
mkdir -p reports/augments
|
||||
mkdir -p storage
|
||||
mkdir -p storage/keystore
|
||||
mkdir -p storage/cache
|
||||
mkdir -p .gocache
|
||||
|
||||
# Check if Go is installed
|
||||
if ! command -v go &> /dev/null; then
|
||||
echo "Error: Go is not installed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if required tools are installed
|
||||
echo "Checking for required tools..."
|
||||
|
||||
# Install golangci-lint if not present
|
||||
if ! command -v golangci-lint &> /dev/null; then
|
||||
echo "Installing golangci-lint..."
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
fi
|
||||
|
||||
# Install gosec if not present
|
||||
if ! command -v gosec &> /dev/null; then
|
||||
echo "Installing gosec..."
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
fi
|
||||
|
||||
# Install govulncheck if not present
|
||||
if ! command -v govulncheck &> /dev/null; then
|
||||
echo "Installing govulncheck..."
|
||||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
fi
|
||||
|
||||
# Install delve if not present
|
||||
if ! command -v dlv &> /dev/null; then
|
||||
echo "Installing delve..."
|
||||
go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
fi
|
||||
|
||||
echo "Development environment setup complete!"
|
||||
SETUP
|
||||
|
||||
# Make setup script executable
|
||||
chmod +x "$PROJECT_NAME/scripts/setup-dev.sh"
|
||||
|
||||
echo "Project template created successfully in $PROJECT_NAME/"
|
||||
echo "To get started:"
|
||||
echo " cd $PROJECT_NAME"
|
||||
echo " make dev-setup"
|
||||
echo " make test"
|
||||
echo " make build"
|
||||
echo " make run"
|
||||
EOF
|
||||
|
||||
chmod +x "$PROJECT_NAME/scripts/setup-dev.sh"
|
||||
|
||||
echo "Project template created successfully in $PROJECT_NAME/"
|
||||
echo "To get started:"
|
||||
echo " cd $PROJECT_NAME"
|
||||
echo " make dev-setup"
|
||||
echo " make test"
|
||||
echo " make build"
|
||||
echo " make run"
|
||||
0
scripts/deploy-arbitrage-contracts.sh
Normal file → Executable file
0
scripts/deploy-arbitrage-contracts.sh
Normal file → Executable file
17
scripts/extract_multicall_fixture.sh
Executable file
17
scripts/extract_multicall_fixture.sh
Executable file
@@ -0,0 +1,17 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
LOG_FILE=${1:-logs/diagnostics/multicall_samples.log}
|
||||
LIMIT=${2:-10}
|
||||
|
||||
if [[ ! -f "$LOG_FILE" ]]; then
|
||||
echo "No diagnostic log found at $LOG_FILE" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Found entries (showing up to $LIMIT):"
|
||||
awk '{print NR"|"$0}' "$LOG_FILE" | tail -n "$LIMIT"
|
||||
|
||||
echo "\nTo fetch calldata for an entry (requires network + API key):"
|
||||
echo " export ARBISCAN_API_KEY=<your_key>"
|
||||
echo " ./scripts/fetch_arbiscan_tx.sh <tx_hash> | jq -r '.result.input'"
|
||||
26
scripts/fetch_arbiscan_tx.sh
Executable file
26
scripts/fetch_arbiscan_tx.sh
Executable file
@@ -0,0 +1,26 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
if [[ $# -ne 1 ]]; then
|
||||
echo "Usage: $0 <tx_hash>" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${ARBISCAN_API_KEY:-}" ]]; then
|
||||
echo "Error: ARBISCAN_API_KEY environment variable is required." >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
TX_HASH="$1"
|
||||
|
||||
# Prefer the newer V2 endpoint; fall back to V1 if it fails (for backwards compatibility)
|
||||
response=$(curl -s "https://api.arbiscan.io/v2/api?module=proxy&action=eth_getTransactionByHash&txhash=${TX_HASH}&apikey=${ARBISCAN_API_KEY}")
|
||||
status=$(echo "$response" | jq -r '.status' 2>/dev/null || echo "")
|
||||
|
||||
if [[ "$status" == "1" || "$status" == "0" && "$response" == *"result"* ]]; then
|
||||
echo "$response"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Fallback to legacy V1 endpoint
|
||||
curl -s "https://api.arbiscan.io/api?module=proxy&action=eth_getTransactionByHash&txhash=${TX_HASH}&apikey=${ARBISCAN_API_KEY}"
|
||||
716
scripts/git-enhanced.sh
Executable file
716
scripts/git-enhanced.sh
Executable file
@@ -0,0 +1,716 @@
|
||||
#!/usr/bin/env bash
|
||||
# Enhanced Git Workflow for Local Self-Contained Development
|
||||
# Provides full branching, forking, PR simulation, and merge workflows
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Configuration
|
||||
DEFAULT_MAIN_BRANCH="master"
|
||||
DEFAULT_DEV_BRANCH="develop"
|
||||
LOCAL_FORK_PREFIX="fork"
|
||||
BACKUP_DIR="$PROJECT_ROOT/.git-backups"
|
||||
|
||||
# Colors for output
|
||||
RED='\033[0;31m'
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
log() {
|
||||
echo -e "${GREEN}[GIT-WORKFLOW]${NC} $*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $*"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Enhanced Git Workflow for MEV Bot - Self-Contained Development Stack
|
||||
|
||||
USAGE: $0 <command> [args]
|
||||
|
||||
BRANCH OPERATIONS:
|
||||
feature <name> - Create feature branch from develop
|
||||
fix <name> - Create hotfix branch from master
|
||||
release <version> - Create release branch
|
||||
branch-list - List all branches with status
|
||||
branch-clean - Clean merged branches
|
||||
|
||||
FORK & PR SIMULATION:
|
||||
fork-create <name> - Create local fork simulation
|
||||
fork-list - List all local forks
|
||||
pr-create <base> - Create PR simulation (local merge preparation)
|
||||
pr-review - Review changes for PR
|
||||
pr-merge <branch> - Merge PR with validation
|
||||
|
||||
MERGE & REBASE:
|
||||
merge <branch> - Smart merge with CI validation
|
||||
rebase <base> - Interactive rebase with conflict resolution
|
||||
sync - Sync current branch with upstream
|
||||
|
||||
CI INTEGRATION:
|
||||
ci-branch - Run CI on current branch
|
||||
ci-pr <branch> - Run CI for PR validation
|
||||
pre-commit - Manual pre-commit validation
|
||||
pre-push - Manual pre-push validation
|
||||
|
||||
BACKUP & RESTORE:
|
||||
backup - Create full git backup
|
||||
restore <backup> - Restore from backup
|
||||
checkpoint <name> - Create named checkpoint
|
||||
|
||||
ADVANCED WORKFLOWS:
|
||||
flow-init - Initialize gitflow-style workflows
|
||||
hotfix <name> - Complete hotfix workflow
|
||||
release-finish <version> - Complete release workflow
|
||||
conflict-resolve - Interactive conflict resolution
|
||||
|
||||
EXAMPLES:
|
||||
$0 feature add-math-optimizations
|
||||
$0 fork-create experimental-trading
|
||||
$0 pr-create develop
|
||||
$0 merge feature/new-arbitrage-engine
|
||||
$0 ci-pr feature/fix-parser-bug
|
||||
EOF
|
||||
}
|
||||
|
||||
# Check if we're in a git repository
|
||||
check_git_repo() {
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
error "Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Get current branch
|
||||
get_current_branch() {
|
||||
git rev-parse --abbrev-ref HEAD
|
||||
}
|
||||
|
||||
# Check if branch exists
|
||||
branch_exists() {
|
||||
git show-ref --verify --quiet "refs/heads/$1"
|
||||
}
|
||||
|
||||
# Run CI pipeline for branch validation
|
||||
run_ci_for_branch() {
|
||||
local branch="$1"
|
||||
log "Running CI validation for branch: $branch"
|
||||
|
||||
# Switch to branch temporarily if not current
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
|
||||
if [[ "$current_branch" != "$branch" ]]; then
|
||||
git checkout "$branch"
|
||||
fi
|
||||
|
||||
# Run appropriate CI level based on branch type
|
||||
if [[ "$branch" =~ ^(feature|fix)/ ]]; then
|
||||
log "Running development CI for $branch"
|
||||
make ci-dev
|
||||
elif [[ "$branch" =~ ^release/ ]] || [[ "$branch" == "$DEFAULT_MAIN_BRANCH" ]]; then
|
||||
log "Running full CI for $branch"
|
||||
make ci-full
|
||||
else
|
||||
log "Running quick CI for $branch"
|
||||
make ci-quick
|
||||
fi
|
||||
|
||||
# Switch back if we changed branches
|
||||
if [[ "$current_branch" != "$branch" ]]; then
|
||||
git checkout "$current_branch"
|
||||
fi
|
||||
}
|
||||
|
||||
# Create feature branch
|
||||
create_feature_branch() {
|
||||
local feature_name="$1"
|
||||
|
||||
if [[ -z "$feature_name" ]]; then
|
||||
error "Feature name required"
|
||||
echo "Usage: $0 feature <name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local branch_name="feature/$feature_name"
|
||||
|
||||
if branch_exists "$branch_name"; then
|
||||
error "Branch $branch_name already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Creating feature branch: $branch_name"
|
||||
|
||||
# Ensure we're on develop and it's up to date
|
||||
if branch_exists "$DEFAULT_DEV_BRANCH"; then
|
||||
git checkout "$DEFAULT_DEV_BRANCH"
|
||||
git pull origin "$DEFAULT_DEV_BRANCH" 2>/dev/null || true
|
||||
else
|
||||
warn "Develop branch doesn't exist, creating from master"
|
||||
git checkout "$DEFAULT_MAIN_BRANCH"
|
||||
git checkout -b "$DEFAULT_DEV_BRANCH"
|
||||
fi
|
||||
|
||||
# Create and switch to feature branch
|
||||
git checkout -b "$branch_name"
|
||||
|
||||
log "✅ Feature branch '$branch_name' created and active"
|
||||
log "💡 Run tests with: make ci-dev"
|
||||
}
|
||||
|
||||
# Create hotfix branch
|
||||
create_fix_branch() {
|
||||
local fix_name="$1"
|
||||
|
||||
if [[ -z "$fix_name" ]]; then
|
||||
error "Fix name required"
|
||||
echo "Usage: $0 fix <name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local branch_name="fix/$fix_name"
|
||||
|
||||
if branch_exists "$branch_name"; then
|
||||
error "Branch $branch_name already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Creating hotfix branch: $branch_name"
|
||||
|
||||
# Create from master
|
||||
git checkout "$DEFAULT_MAIN_BRANCH"
|
||||
git pull origin "$DEFAULT_MAIN_BRANCH" 2>/dev/null || true
|
||||
git checkout -b "$branch_name"
|
||||
|
||||
log "✅ Hotfix branch '$branch_name' created and active"
|
||||
log "💡 Run tests with: make ci-full"
|
||||
}
|
||||
|
||||
# Create local fork simulation
|
||||
create_fork() {
|
||||
local fork_name="$1"
|
||||
|
||||
if [[ -z "$fork_name" ]]; then
|
||||
error "Fork name required"
|
||||
echo "Usage: $0 fork-create <name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local fork_branch="${LOCAL_FORK_PREFIX}/$fork_name"
|
||||
|
||||
if branch_exists "$fork_branch"; then
|
||||
error "Fork $fork_branch already exists"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Creating local fork: $fork_branch"
|
||||
|
||||
# Create orphan branch for fork simulation
|
||||
git checkout --orphan "$fork_branch"
|
||||
git reset --hard "$DEFAULT_MAIN_BRANCH"
|
||||
|
||||
# Create initial commit for fork
|
||||
git commit --allow-empty -m "chore: initialize fork '$fork_name'"
|
||||
|
||||
log "✅ Local fork '$fork_name' created"
|
||||
log "💡 This simulates a separate fork for experimental development"
|
||||
}
|
||||
|
||||
# List all branches with status
|
||||
list_branches() {
|
||||
log "Repository branch overview:"
|
||||
echo ""
|
||||
|
||||
echo "📋 Local Branches:"
|
||||
git branch -v
|
||||
|
||||
echo ""
|
||||
echo "🔀 Remote Branches:"
|
||||
git branch -rv 2>/dev/null || echo "No remote branches"
|
||||
|
||||
echo ""
|
||||
echo "🍴 Local Forks:"
|
||||
git branch | grep "^ $LOCAL_FORK_PREFIX/" || echo "No local forks"
|
||||
|
||||
echo ""
|
||||
echo "📊 Branch Status:"
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
echo "Current: $current_branch"
|
||||
|
||||
# Check if current branch has uncommitted changes
|
||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
||||
warn "Current branch has uncommitted changes"
|
||||
fi
|
||||
|
||||
# Check if current branch is ahead/behind
|
||||
local upstream
|
||||
upstream=$(git rev-parse --abbrev-ref @{u} 2>/dev/null || echo "")
|
||||
if [[ -n "$upstream" ]]; then
|
||||
local ahead behind
|
||||
ahead=$(git rev-list --count "$upstream..HEAD" 2>/dev/null || echo "0")
|
||||
behind=$(git rev-list --count "HEAD..$upstream" 2>/dev/null || echo "0")
|
||||
|
||||
if [[ "$ahead" -gt 0 ]]; then
|
||||
info "Current branch is $ahead commits ahead of $upstream"
|
||||
fi
|
||||
if [[ "$behind" -gt 0 ]]; then
|
||||
warn "Current branch is $behind commits behind $upstream"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
# Create PR simulation (prepare for merge)
|
||||
create_pr() {
|
||||
local target_branch="$1"
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
|
||||
if [[ -z "$target_branch" ]]; then
|
||||
error "Target branch required"
|
||||
echo "Usage: $0 pr-create <target-branch>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if ! branch_exists "$target_branch"; then
|
||||
error "Target branch '$target_branch' does not exist"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Creating PR simulation: $current_branch → $target_branch"
|
||||
|
||||
# Run CI validation for PR
|
||||
run_ci_for_branch "$current_branch"
|
||||
|
||||
# Show diff summary
|
||||
echo ""
|
||||
log "PR Summary:"
|
||||
echo "From: $current_branch"
|
||||
echo "To: $target_branch"
|
||||
echo ""
|
||||
|
||||
echo "📝 Changed files:"
|
||||
git diff --name-status "$target_branch..$current_branch"
|
||||
|
||||
echo ""
|
||||
echo "📊 Commit summary:"
|
||||
git log --oneline "$target_branch..$current_branch"
|
||||
|
||||
echo ""
|
||||
echo "🔍 Conflict check:"
|
||||
if git merge-tree "$(git merge-base "$target_branch" "$current_branch")" "$target_branch" "$current_branch" | grep -q "<<<<<<< "; then
|
||||
warn "Potential merge conflicts detected"
|
||||
echo "Run: $0 conflict-resolve"
|
||||
else
|
||||
log "No merge conflicts detected"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log "✅ PR simulation ready"
|
||||
log "Next steps:"
|
||||
log " - Review changes: $0 pr-review"
|
||||
log " - Merge PR: $0 pr-merge $target_branch"
|
||||
}
|
||||
|
||||
# Review PR changes
|
||||
review_pr() {
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
|
||||
log "Reviewing changes for: $current_branch"
|
||||
|
||||
# Show detailed diff
|
||||
echo ""
|
||||
echo "📝 Detailed changes:"
|
||||
git diff develop.."$current_branch" --stat
|
||||
|
||||
echo ""
|
||||
read -p "View full diff? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
git diff develop.."$current_branch"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log "Code quality checks:"
|
||||
|
||||
# Run linting
|
||||
if make ci-quick; then
|
||||
log "✅ Code quality checks passed"
|
||||
else
|
||||
error "❌ Code quality checks failed"
|
||||
echo "Fix issues before merging"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Merge PR with validation
|
||||
merge_pr() {
|
||||
local target_branch="$1"
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
|
||||
if [[ -z "$target_branch" ]]; then
|
||||
error "Target branch required"
|
||||
echo "Usage: $0 pr-merge <target-branch>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Merging PR: $current_branch → $target_branch"
|
||||
|
||||
# Final CI validation
|
||||
log "Running final CI validation..."
|
||||
run_ci_for_branch "$current_branch"
|
||||
|
||||
# Create backup before merge
|
||||
local backup_name="before-merge-$(date +%Y%m%d-%H%M%S)"
|
||||
create_backup "$backup_name"
|
||||
|
||||
# Switch to target branch and merge
|
||||
git checkout "$target_branch"
|
||||
|
||||
# Update target branch
|
||||
git pull origin "$target_branch" 2>/dev/null || true
|
||||
|
||||
# Perform merge
|
||||
if git merge --no-ff "$current_branch" -m "Merge branch '$current_branch' into $target_branch
|
||||
|
||||
🤖 Generated with [Claude Code](https://claude.com/claude-code)
|
||||
Co-Authored-By: Claude <noreply@anthropic.com>"; then
|
||||
log "✅ Merge completed successfully"
|
||||
|
||||
# Run post-merge CI
|
||||
log "Running post-merge validation..."
|
||||
run_ci_for_branch "$target_branch"
|
||||
|
||||
# Optional: Delete merged branch
|
||||
read -p "Delete merged branch '$current_branch'? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
git branch -d "$current_branch"
|
||||
log "Deleted merged branch: $current_branch"
|
||||
fi
|
||||
else
|
||||
error "Merge failed - conflicts need resolution"
|
||||
echo "Run: $0 conflict-resolve"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Smart merge with CI validation
|
||||
smart_merge() {
|
||||
local source_branch="$1"
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
|
||||
if [[ -z "$source_branch" ]]; then
|
||||
error "Source branch required"
|
||||
echo "Usage: $0 merge <source-branch>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Smart merge: $source_branch → $current_branch"
|
||||
|
||||
# Validate both branches
|
||||
run_ci_for_branch "$current_branch"
|
||||
run_ci_for_branch "$source_branch"
|
||||
|
||||
# Create backup
|
||||
local backup_name="before-smart-merge-$(date +%Y%m%d-%H%M%S)"
|
||||
create_backup "$backup_name"
|
||||
|
||||
# Perform merge
|
||||
if git merge "$source_branch"; then
|
||||
log "✅ Smart merge completed"
|
||||
run_ci_for_branch "$current_branch"
|
||||
else
|
||||
error "Merge conflicts detected"
|
||||
echo "Run: $0 conflict-resolve"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Interactive conflict resolution
|
||||
resolve_conflicts() {
|
||||
log "Interactive conflict resolution"
|
||||
|
||||
# Check if we're in a merge
|
||||
if [[ ! -f .git/MERGE_HEAD ]]; then
|
||||
error "No merge in progress"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Show conflicted files
|
||||
echo ""
|
||||
echo "📝 Conflicted files:"
|
||||
git diff --name-only --diff-filter=U
|
||||
|
||||
echo ""
|
||||
echo "🔧 Resolution options:"
|
||||
echo "1) Open merge tool (if configured)"
|
||||
echo "2) Show conflicts in terminal"
|
||||
echo "3) Abort merge"
|
||||
|
||||
read -p "Choose option (1-3): " -n 1 -r
|
||||
echo
|
||||
|
||||
case $REPLY in
|
||||
1)
|
||||
if git config merge.tool >/dev/null; then
|
||||
git mergetool
|
||||
else
|
||||
warn "No merge tool configured"
|
||||
echo "Configure with: git config merge.tool <tool>"
|
||||
fi
|
||||
;;
|
||||
2)
|
||||
echo ""
|
||||
echo "📝 Conflicts:"
|
||||
git diff --diff-filter=U
|
||||
;;
|
||||
3)
|
||||
git merge --abort
|
||||
log "Merge aborted"
|
||||
return
|
||||
;;
|
||||
*)
|
||||
error "Invalid option"
|
||||
return
|
||||
;;
|
||||
esac
|
||||
|
||||
# After resolution
|
||||
echo ""
|
||||
read -p "Have conflicts been resolved? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
git add .
|
||||
git commit --no-edit
|
||||
log "✅ Merge completed"
|
||||
|
||||
# Run CI after merge
|
||||
run_ci_for_branch "$(get_current_branch)"
|
||||
fi
|
||||
}
|
||||
|
||||
# Create backup
|
||||
create_backup() {
|
||||
local backup_name="${1:-backup-$(date +%Y%m%d-%H%M%S)}"
|
||||
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
log "Creating backup: $backup_name"
|
||||
|
||||
# Create git bundle
|
||||
git bundle create "$BACKUP_DIR/$backup_name.bundle" --all
|
||||
|
||||
# Create stash backup if there are changes
|
||||
if ! git diff --quiet || ! git diff --cached --quiet; then
|
||||
git stash push -m "Backup stash: $backup_name"
|
||||
echo "backup-stash-$backup_name" > "$BACKUP_DIR/$backup_name.stash"
|
||||
fi
|
||||
|
||||
# Save current branch info
|
||||
echo "$(get_current_branch)" > "$BACKUP_DIR/$backup_name.branch"
|
||||
|
||||
log "✅ Backup created: $backup_name"
|
||||
log "Location: $BACKUP_DIR/"
|
||||
}
|
||||
|
||||
# Restore from backup
|
||||
restore_backup() {
|
||||
local backup_name="$1"
|
||||
|
||||
if [[ -z "$backup_name" ]]; then
|
||||
error "Backup name required"
|
||||
echo "Available backups:"
|
||||
ls -1 "$BACKUP_DIR"/*.bundle 2>/dev/null | sed 's/.*\///' | sed 's/\.bundle$//' || echo "No backups found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local bundle_file="$BACKUP_DIR/$backup_name.bundle"
|
||||
|
||||
if [[ ! -f "$bundle_file" ]]; then
|
||||
error "Backup not found: $backup_name"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
warn "This will restore git state from backup: $backup_name"
|
||||
read -p "Continue? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Restore cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Restoring from backup: $backup_name"
|
||||
|
||||
# Restore from bundle
|
||||
git fetch "$bundle_file"
|
||||
|
||||
# Restore branch if saved
|
||||
if [[ -f "$BACKUP_DIR/$backup_name.branch" ]]; then
|
||||
local saved_branch
|
||||
saved_branch=$(cat "$BACKUP_DIR/$backup_name.branch")
|
||||
if branch_exists "$saved_branch"; then
|
||||
git checkout "$saved_branch"
|
||||
fi
|
||||
fi
|
||||
|
||||
log "✅ Backup restored: $backup_name"
|
||||
}
|
||||
|
||||
# Run CI for current branch
|
||||
run_ci_branch() {
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
run_ci_for_branch "$current_branch"
|
||||
}
|
||||
|
||||
# Run CI for PR validation
|
||||
run_ci_pr() {
|
||||
local branch="$1"
|
||||
|
||||
if [[ -z "$branch" ]]; then
|
||||
branch=$(get_current_branch)
|
||||
fi
|
||||
|
||||
log "Running PR validation CI for: $branch"
|
||||
run_ci_for_branch "$branch"
|
||||
|
||||
# Additional PR-specific checks
|
||||
log "Running PR-specific validations..."
|
||||
|
||||
# Check commit messages
|
||||
log "Checking commit message format..."
|
||||
git log --oneline "develop..$branch" | while read -r line; do
|
||||
if [[ ! "$line" =~ ^[a-f0-9]+\ (feat|fix|chore|docs|style|refactor|perf|test)(\(.+\))?:\ .+ ]]; then
|
||||
warn "Commit message format: $line"
|
||||
warn "Should follow: type(scope): description"
|
||||
fi
|
||||
done
|
||||
|
||||
log "✅ PR validation completed"
|
||||
}
|
||||
|
||||
# Clean merged branches
|
||||
clean_branches() {
|
||||
log "Cleaning merged branches..."
|
||||
|
||||
# Get merged branches (excluding master, develop, and current)
|
||||
local current_branch
|
||||
current_branch=$(get_current_branch)
|
||||
|
||||
local merged_branches
|
||||
merged_branches=$(git branch --merged "$DEFAULT_MAIN_BRANCH" | grep -v "$DEFAULT_MAIN_BRANCH" | grep -v "$DEFAULT_DEV_BRANCH" | grep -v "^* $current_branch" | grep -v "^ $current_branch" | sed 's/^[ *]*//')
|
||||
|
||||
if [[ -z "$merged_branches" ]]; then
|
||||
log "No merged branches to clean"
|
||||
return
|
||||
fi
|
||||
|
||||
echo "📝 Merged branches to delete:"
|
||||
echo "$merged_branches"
|
||||
|
||||
echo ""
|
||||
read -p "Delete these branches? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "$merged_branches" | while read -r branch; do
|
||||
if [[ -n "$branch" ]]; then
|
||||
git branch -d "$branch"
|
||||
log "Deleted: $branch"
|
||||
fi
|
||||
done
|
||||
fi
|
||||
}
|
||||
|
||||
# Main command dispatcher
|
||||
main() {
|
||||
check_git_repo
|
||||
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
local command="$1"
|
||||
shift
|
||||
|
||||
case "$command" in
|
||||
feature)
|
||||
create_feature_branch "$@"
|
||||
;;
|
||||
fix)
|
||||
create_fix_branch "$@"
|
||||
;;
|
||||
fork-create)
|
||||
create_fork "$@"
|
||||
;;
|
||||
fork-list)
|
||||
git branch | grep "^ $LOCAL_FORK_PREFIX/" || echo "No local forks"
|
||||
;;
|
||||
pr-create)
|
||||
create_pr "$@"
|
||||
;;
|
||||
pr-review)
|
||||
review_pr
|
||||
;;
|
||||
pr-merge)
|
||||
merge_pr "$@"
|
||||
;;
|
||||
merge)
|
||||
smart_merge "$@"
|
||||
;;
|
||||
conflict-resolve)
|
||||
resolve_conflicts
|
||||
;;
|
||||
branch-list)
|
||||
list_branches
|
||||
;;
|
||||
branch-clean)
|
||||
clean_branches
|
||||
;;
|
||||
backup)
|
||||
create_backup "$@"
|
||||
;;
|
||||
restore)
|
||||
restore_backup "$@"
|
||||
;;
|
||||
ci-branch)
|
||||
run_ci_branch
|
||||
;;
|
||||
ci-pr)
|
||||
run_ci_pr "$@"
|
||||
;;
|
||||
pre-commit)
|
||||
make ci-precommit
|
||||
;;
|
||||
pre-push)
|
||||
make ci-dev
|
||||
;;
|
||||
*)
|
||||
error "Unknown command: $command"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
285
scripts/git-hooks-setup.sh
Executable file
285
scripts/git-hooks-setup.sh
Executable file
@@ -0,0 +1,285 @@
|
||||
#!/usr/bin/env bash
|
||||
# Git Hooks Setup for MEV Bot CI/CD Integration
|
||||
# Creates git hooks that integrate with the CI/CD pipeline
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
HOOKS_DIR="$PROJECT_ROOT/.git/hooks"
|
||||
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
log() {
|
||||
echo "[HOOKS-SETUP] $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo "[ERROR] $*" >&2
|
||||
}
|
||||
|
||||
# Check if we're in a git repository
|
||||
if ! git rev-parse --git-dir >/dev/null 2>&1; then
|
||||
error "Not in a git repository"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Setting up Git hooks integration with CI/CD pipeline..."
|
||||
|
||||
# Create hooks directory if it doesn't exist
|
||||
mkdir -p "$HOOKS_DIR"
|
||||
|
||||
# Pre-commit hook
|
||||
cat > "$HOOKS_DIR/pre-commit" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Pre-commit hook - Fast validation before commit
|
||||
|
||||
set -e
|
||||
|
||||
echo "🔍 Running pre-commit validation..."
|
||||
|
||||
# Check if we have staged files
|
||||
if git diff --cached --quiet; then
|
||||
echo "No staged changes to validate"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Run fast CI validation
|
||||
if command -v make >/dev/null 2>&1; then
|
||||
echo "Running pre-commit CI pipeline..."
|
||||
make ci-precommit
|
||||
else
|
||||
echo "Running basic checks..."
|
||||
|
||||
# Basic Go checks
|
||||
if command -v go >/dev/null 2>&1; then
|
||||
echo "Building..."
|
||||
go build ./cmd/mev-bot
|
||||
|
||||
echo "Running tests..."
|
||||
go test ./pkg/... -short
|
||||
|
||||
echo "Checking format..."
|
||||
if ! gofmt -l . | grep -q .; then
|
||||
echo "✅ Code formatting is clean"
|
||||
else
|
||||
echo "❌ Code needs formatting:"
|
||||
gofmt -l .
|
||||
echo "Run: gofmt -w ."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Running vet..."
|
||||
go vet ./...
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Pre-commit validation passed"
|
||||
EOF
|
||||
|
||||
# Pre-push hook
|
||||
cat > "$HOOKS_DIR/pre-push" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Pre-push hook - Comprehensive validation before push
|
||||
|
||||
set -e
|
||||
|
||||
echo "🚀 Running pre-push validation..."
|
||||
|
||||
# Get the branch being pushed
|
||||
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
echo "Validating branch: $branch"
|
||||
|
||||
# Run appropriate CI based on branch type
|
||||
if command -v make >/dev/null 2>&1; then
|
||||
if [[ "$branch" =~ ^(feature|fix)/ ]]; then
|
||||
echo "Running development CI for feature/fix branch..."
|
||||
make ci-dev
|
||||
elif [[ "$branch" =~ ^release/ ]] || [[ "$branch" == "master" ]] || [[ "$branch" == "main" ]]; then
|
||||
echo "Running full CI for release/main branch..."
|
||||
make ci-full
|
||||
else
|
||||
echo "Running quick CI for other branches..."
|
||||
make ci-quick
|
||||
fi
|
||||
else
|
||||
echo "Running basic validation..."
|
||||
|
||||
if command -v go >/dev/null 2>&1; then
|
||||
echo "Building..."
|
||||
go build ./cmd/mev-bot
|
||||
|
||||
echo "Running full test suite..."
|
||||
go test ./...
|
||||
|
||||
echo "Running static analysis..."
|
||||
go vet ./...
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "✅ Pre-push validation passed"
|
||||
EOF
|
||||
|
||||
# Post-commit hook
|
||||
cat > "$HOOKS_DIR/post-commit" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Post-commit hook - Optional post-commit actions
|
||||
|
||||
# Get commit info
|
||||
commit_hash=$(git rev-parse HEAD)
|
||||
commit_msg=$(git log -1 --pretty=%B)
|
||||
branch=$(git rev-parse --abbrev-ref HEAD)
|
||||
|
||||
echo "📝 Post-commit: $commit_hash on $branch"
|
||||
|
||||
# Optional: Run quick smoke test after commit
|
||||
if [[ "$commit_msg" =~ ^(feat|fix|perf): ]]; then
|
||||
echo "Running smoke test for significant changes..."
|
||||
if command -v make >/dev/null 2>&1; then
|
||||
timeout 30 make ci-precommit || echo "Smoke test completed"
|
||||
fi
|
||||
fi
|
||||
EOF
|
||||
|
||||
# Prepare-commit-msg hook
|
||||
cat > "$HOOKS_DIR/prepare-commit-msg" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Prepare commit message hook - Add conventional commit format help
|
||||
|
||||
commit_file="$1"
|
||||
commit_source="$2"
|
||||
|
||||
# Only add template for regular commits (not merges, amendments, etc.)
|
||||
if [[ "$commit_source" == "" ]] || [[ "$commit_source" == "template" ]]; then
|
||||
# Get the branch name
|
||||
branch=$(git rev-parse --abbrev-ref HEAD 2>/dev/null || echo "main")
|
||||
|
||||
# Add conventional commit template if message is empty
|
||||
if [[ ! -s "$commit_file" ]]; then
|
||||
cat >> "$commit_file" << 'TEMPLATE'
|
||||
|
||||
# Conventional Commits Format:
|
||||
# type(scope): description
|
||||
#
|
||||
# Types: feat, fix, docs, style, refactor, perf, test, chore
|
||||
# Example: feat(parser): add support for multicall transactions
|
||||
#
|
||||
# Body (optional):
|
||||
# - Explain what and why vs. how
|
||||
# - Include motivation for the change
|
||||
# - Contrast with previous behavior
|
||||
#
|
||||
# Footer (optional):
|
||||
# - Breaking changes: BREAKING CHANGE: <description>
|
||||
# - Issues: Closes #123, Fixes #456
|
||||
|
||||
TEMPLATE
|
||||
fi
|
||||
fi
|
||||
EOF
|
||||
|
||||
# Post-merge hook
|
||||
cat > "$HOOKS_DIR/post-merge" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Post-merge hook - Actions after merge
|
||||
|
||||
echo "🔀 Post-merge validation..."
|
||||
|
||||
# Run CI after merge to ensure integration is clean
|
||||
if command -v make >/dev/null 2>&1; then
|
||||
echo "Running post-merge CI validation..."
|
||||
make ci-dev
|
||||
else
|
||||
echo "Running basic post-merge checks..."
|
||||
if command -v go >/dev/null 2>&1; then
|
||||
go build ./cmd/mev-bot
|
||||
go test ./pkg/... -short
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check if dependencies changed
|
||||
if git diff HEAD@{1} --name-only | grep -q "go.mod\|go.sum"; then
|
||||
echo "📦 Dependencies changed, updating..."
|
||||
go mod tidy
|
||||
go mod verify
|
||||
fi
|
||||
|
||||
echo "✅ Post-merge validation completed"
|
||||
EOF
|
||||
|
||||
# Pre-rebase hook
|
||||
cat > "$HOOKS_DIR/pre-rebase" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Pre-rebase hook - Validation before rebase
|
||||
|
||||
upstream="$1"
|
||||
branch="$2"
|
||||
|
||||
echo "🔄 Pre-rebase validation..."
|
||||
echo "Rebasing: ${branch:-$(git rev-parse --abbrev-ref HEAD)} onto $upstream"
|
||||
|
||||
# Warn about rebasing public branches
|
||||
current_branch=${branch:-$(git rev-parse --abbrev-ref HEAD)}
|
||||
if [[ "$current_branch" == "master" ]] || [[ "$current_branch" == "main" ]] || [[ "$current_branch" == "develop" ]]; then
|
||||
echo "⚠️ WARNING: Rebasing public branch '$current_branch'"
|
||||
echo "This may rewrite history. Continue? (y/N)"
|
||||
read -r response
|
||||
if [[ ! "$response" =~ ^[Yy]$ ]]; then
|
||||
echo "Rebase cancelled"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Run quick validation
|
||||
if command -v make >/dev/null 2>&1; then
|
||||
make ci-precommit
|
||||
fi
|
||||
|
||||
echo "✅ Pre-rebase validation passed"
|
||||
EOF
|
||||
|
||||
# Make all hooks executable
|
||||
chmod +x "$HOOKS_DIR"/*
|
||||
|
||||
log "✅ Git hooks installed:"
|
||||
log " - pre-commit: Fast validation (build, test, format)"
|
||||
log " - pre-push: Comprehensive CI validation"
|
||||
log " - post-commit: Optional smoke tests"
|
||||
log " - prepare-commit-msg: Conventional commit template"
|
||||
log " - post-merge: Integration validation"
|
||||
log " - pre-rebase: Safety checks for public branches"
|
||||
|
||||
echo ""
|
||||
log "🎯 Hook Integration Features:"
|
||||
log " - Automatic CI pipeline integration"
|
||||
log " - Branch-specific validation levels"
|
||||
log " - Conventional commit message formatting"
|
||||
log " - Dependency change detection"
|
||||
log " - Safety checks for public branch operations"
|
||||
|
||||
echo ""
|
||||
log "💡 To disable hooks temporarily:"
|
||||
log " git commit --no-verify"
|
||||
log " git push --no-verify"
|
||||
|
||||
echo ""
|
||||
log "🔧 To customize hooks, edit files in: .git/hooks/"
|
||||
|
||||
# Test the hooks
|
||||
echo ""
|
||||
log "Testing hook installation..."
|
||||
|
||||
if [[ -x "$HOOKS_DIR/pre-commit" ]]; then
|
||||
log "✅ Pre-commit hook installed and executable"
|
||||
else
|
||||
error "❌ Pre-commit hook installation failed"
|
||||
fi
|
||||
|
||||
if [[ -x "$HOOKS_DIR/pre-push" ]]; then
|
||||
log "✅ Pre-push hook installed and executable"
|
||||
else
|
||||
error "❌ Pre-push hook installation failed"
|
||||
fi
|
||||
|
||||
log "🎉 Git hooks setup completed successfully!"
|
||||
log "Next commit will use the new validation pipeline."
|
||||
523
scripts/git-local-server.sh
Executable file
523
scripts/git-local-server.sh
Executable file
@@ -0,0 +1,523 @@
|
||||
#!/usr/bin/env bash
|
||||
# Local Git Server Simulation for Team Workflows
|
||||
# Creates a local bare repository to simulate a remote server for testing git workflows
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
LOCAL_SERVER_DIR="$PROJECT_ROOT/.git-local-server"
|
||||
BARE_REPO_DIR="$LOCAL_SERVER_DIR/mev-bot.git"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
BLUE='\033[0;34m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() {
|
||||
echo -e "${GREEN}[GIT-SERVER]${NC} $*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $*"
|
||||
}
|
||||
|
||||
usage() {
|
||||
cat << EOF
|
||||
Local Git Server Simulation for MEV Bot Development
|
||||
|
||||
USAGE: $0 <command> [args]
|
||||
|
||||
SERVER MANAGEMENT:
|
||||
init - Initialize local git server
|
||||
start - Start local git server (if using daemon)
|
||||
stop - Stop local git server
|
||||
status - Show server status
|
||||
clean - Clean server data
|
||||
|
||||
REPOSITORY OPERATIONS:
|
||||
clone-fresh <name> - Clone fresh copy from local server
|
||||
push-all - Push all branches to local server
|
||||
pull-all - Pull all branches from local server
|
||||
sync-remotes - Sync with local server
|
||||
|
||||
TEAM SIMULATION:
|
||||
simulate-dev <name> - Simulate developer workflow
|
||||
simulate-pr <branch> - Simulate PR workflow
|
||||
simulate-conflict - Create merge conflict scenario
|
||||
simulate-team - Multi-developer simulation
|
||||
|
||||
EXAMPLES:
|
||||
$0 init # Setup local git server
|
||||
$0 clone-fresh alice # Create alice's working copy
|
||||
$0 simulate-dev bob # Simulate bob's development
|
||||
$0 simulate-pr feature/new-algo # Simulate PR workflow
|
||||
EOF
|
||||
}
|
||||
|
||||
# Initialize local git server
|
||||
init_server() {
|
||||
log "Initializing local git server..."
|
||||
|
||||
# Create server directory
|
||||
mkdir -p "$LOCAL_SERVER_DIR"
|
||||
|
||||
# Create bare repository
|
||||
if [[ -d "$BARE_REPO_DIR" ]]; then
|
||||
warn "Local server already exists at: $BARE_REPO_DIR"
|
||||
read -p "Reinitialize? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
exit 0
|
||||
fi
|
||||
rm -rf "$BARE_REPO_DIR"
|
||||
fi
|
||||
|
||||
# Initialize bare repository
|
||||
git init --bare "$BARE_REPO_DIR"
|
||||
|
||||
# Push current repository to server
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Add local server as remote if not exists
|
||||
if ! git remote get-url local-server >/dev/null 2>&1; then
|
||||
git remote add local-server "$BARE_REPO_DIR"
|
||||
else
|
||||
git remote set-url local-server "$BARE_REPO_DIR"
|
||||
fi
|
||||
|
||||
# Push all branches
|
||||
log "Pushing current repository to local server..."
|
||||
git push local-server --all 2>/dev/null || true
|
||||
git push local-server --tags 2>/dev/null || true
|
||||
|
||||
# Create post-receive hook for CI integration
|
||||
cat > "$BARE_REPO_DIR/hooks/post-receive" << 'EOF'
|
||||
#!/usr/bin/env bash
|
||||
# Post-receive hook - Run CI on pushes to main branches
|
||||
|
||||
while read oldrev newrev refname; do
|
||||
branch=$(echo $refname | sed -n 's/^refs\/heads\///p')
|
||||
|
||||
if [[ "$branch" == "master" ]] || [[ "$branch" == "main" ]] || [[ "$branch" == "develop" ]]; then
|
||||
echo "🚀 Running CI for $branch branch..."
|
||||
|
||||
# Create temporary checkout
|
||||
temp_dir=$(mktemp -d)
|
||||
git --git-dir="$PWD" --work-tree="$temp_dir" checkout -f "$branch"
|
||||
|
||||
# Run CI in the temporary directory
|
||||
(
|
||||
cd "$temp_dir"
|
||||
if [[ -f "Makefile" ]] && command -v make >/dev/null 2>&1; then
|
||||
echo "Running CI pipeline..."
|
||||
make ci-quick || echo "CI failed for $branch"
|
||||
else
|
||||
echo "No CI configuration found"
|
||||
fi
|
||||
)
|
||||
|
||||
# Cleanup
|
||||
rm -rf "$temp_dir"
|
||||
fi
|
||||
done
|
||||
EOF
|
||||
|
||||
chmod +x "$BARE_REPO_DIR/hooks/post-receive"
|
||||
|
||||
log "✅ Local git server initialized at: $BARE_REPO_DIR"
|
||||
log "📍 Remote added as: local-server"
|
||||
log "🎯 Server URL: $BARE_REPO_DIR"
|
||||
|
||||
# Create server info file
|
||||
cat > "$LOCAL_SERVER_DIR/server-info.txt" << EOF
|
||||
MEV Bot Local Git Server
|
||||
========================
|
||||
|
||||
Repository: $BARE_REPO_DIR
|
||||
Remote name: local-server
|
||||
Initialized: $(date)
|
||||
|
||||
Available commands:
|
||||
git clone $BARE_REPO_DIR <directory>
|
||||
git remote add origin $BARE_REPO_DIR
|
||||
git push local-server <branch>
|
||||
git pull local-server <branch>
|
||||
|
||||
Hooks installed:
|
||||
- post-receive: CI integration for main branches
|
||||
EOF
|
||||
|
||||
log "📋 Server info saved to: $LOCAL_SERVER_DIR/server-info.txt"
|
||||
}
|
||||
|
||||
# Show server status
|
||||
show_status() {
|
||||
if [[ ! -d "$BARE_REPO_DIR" ]]; then
|
||||
error "Local git server not initialized"
|
||||
echo "Run: $0 init"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Local Git Server Status"
|
||||
echo ""
|
||||
|
||||
echo "📍 Server Location: $BARE_REPO_DIR"
|
||||
echo "📊 Repository Size: $(du -sh "$BARE_REPO_DIR" 2>/dev/null | cut -f1)"
|
||||
echo ""
|
||||
|
||||
echo "🌿 Branches:"
|
||||
git --git-dir="$BARE_REPO_DIR" branch -a || echo "No branches"
|
||||
|
||||
echo ""
|
||||
echo "🏷️ Tags:"
|
||||
git --git-dir="$BARE_REPO_DIR" tag -l | head -10 || echo "No tags"
|
||||
|
||||
echo ""
|
||||
echo "📈 Recent Activity:"
|
||||
git --git-dir="$BARE_REPO_DIR" log --oneline --all -10 2>/dev/null || echo "No commits"
|
||||
|
||||
echo ""
|
||||
echo "🔗 Remote Configuration in Main Repo:"
|
||||
cd "$PROJECT_ROOT"
|
||||
if git remote get-url local-server >/dev/null 2>&1; then
|
||||
echo "✅ local-server: $(git remote get-url local-server)"
|
||||
else
|
||||
echo "❌ local-server remote not configured"
|
||||
fi
|
||||
}
|
||||
|
||||
# Clone fresh copy from local server
|
||||
clone_fresh() {
|
||||
local clone_name="$1"
|
||||
|
||||
if [[ -z "$clone_name" ]]; then
|
||||
error "Clone name required"
|
||||
echo "Usage: $0 clone-fresh <name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ! -d "$BARE_REPO_DIR" ]]; then
|
||||
error "Local git server not initialized"
|
||||
echo "Run: $0 init"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
local clone_dir="$LOCAL_SERVER_DIR/clones/$clone_name"
|
||||
|
||||
if [[ -d "$clone_dir" ]]; then
|
||||
warn "Clone already exists: $clone_dir"
|
||||
read -p "Remove and re-clone? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||
rm -rf "$clone_dir"
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
fi
|
||||
|
||||
log "Creating fresh clone: $clone_name"
|
||||
|
||||
# Create clone directory
|
||||
mkdir -p "$(dirname "$clone_dir")"
|
||||
|
||||
# Clone from local server
|
||||
git clone "$BARE_REPO_DIR" "$clone_dir"
|
||||
|
||||
# Set up useful configuration
|
||||
cd "$clone_dir"
|
||||
|
||||
# Configure git for this clone
|
||||
git config user.name "Developer $clone_name"
|
||||
git config user.email "$clone_name@mev-bot.local"
|
||||
|
||||
# Add convenience aliases
|
||||
git config alias.st status
|
||||
git config alias.co checkout
|
||||
git config alias.br branch
|
||||
git config alias.ci commit
|
||||
git config alias.up "pull --rebase"
|
||||
|
||||
log "✅ Fresh clone created: $clone_dir"
|
||||
log "💡 To use this clone:"
|
||||
log " cd $clone_dir"
|
||||
log " git checkout -b feature/your-feature"
|
||||
log " # ... make changes ..."
|
||||
log " git push origin feature/your-feature"
|
||||
}
|
||||
|
||||
# Simulate developer workflow
|
||||
simulate_dev() {
|
||||
local dev_name="$1"
|
||||
|
||||
if [[ -z "$dev_name" ]]; then
|
||||
error "Developer name required"
|
||||
echo "Usage: $0 simulate-dev <name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Simulating developer workflow for: $dev_name"
|
||||
|
||||
# Create or use existing clone
|
||||
local clone_dir="$LOCAL_SERVER_DIR/clones/$dev_name"
|
||||
|
||||
if [[ ! -d "$clone_dir" ]]; then
|
||||
log "Creating clone for $dev_name..."
|
||||
clone_fresh "$dev_name"
|
||||
fi
|
||||
|
||||
cd "$clone_dir"
|
||||
|
||||
# Simulate development workflow
|
||||
log "🔄 Pulling latest changes..."
|
||||
git checkout develop 2>/dev/null || git checkout master
|
||||
git pull origin "$(git branch --show-current)"
|
||||
|
||||
# Create feature branch
|
||||
local feature_name="feature/$dev_name-$(date +%H%M%S)"
|
||||
log "🌿 Creating feature branch: $feature_name"
|
||||
git checkout -b "$feature_name"
|
||||
|
||||
# Simulate some development
|
||||
echo "// Development by $dev_name at $(date)" >> "dev-notes-$dev_name.txt"
|
||||
echo "Implemented new feature for MEV optimization" >> "dev-notes-$dev_name.txt"
|
||||
git add "dev-notes-$dev_name.txt"
|
||||
|
||||
# Commit with conventional format
|
||||
git commit -m "feat($dev_name): implement MEV optimization feature
|
||||
|
||||
- Add new optimization algorithm
|
||||
- Improve performance by 15%
|
||||
- Update documentation
|
||||
|
||||
Closes #123"
|
||||
|
||||
# Run CI before push
|
||||
log "🧪 Running CI validation..."
|
||||
if [[ -f "../../../Makefile" ]]; then
|
||||
make -C "../../.." ci-quick 2>/dev/null || warn "CI validation failed"
|
||||
fi
|
||||
|
||||
# Push feature branch
|
||||
log "🚀 Pushing feature branch..."
|
||||
git push origin "$feature_name"
|
||||
|
||||
log "✅ Developer workflow completed for $dev_name"
|
||||
log "📂 Working directory: $clone_dir"
|
||||
log "🌿 Feature branch: $feature_name"
|
||||
log "💡 Next: Simulate PR with: $0 simulate-pr $feature_name"
|
||||
}
|
||||
|
||||
# Simulate PR workflow
|
||||
simulate_pr() {
|
||||
local branch_name="$1"
|
||||
|
||||
if [[ -z "$branch_name" ]]; then
|
||||
error "Branch name required"
|
||||
echo "Usage: $0 simulate-pr <branch-name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Simulating PR workflow for branch: $branch_name"
|
||||
|
||||
# Find which clone has this branch
|
||||
local clone_dir=""
|
||||
for dir in "$LOCAL_SERVER_DIR/clones"/*; do
|
||||
if [[ -d "$dir" ]]; then
|
||||
cd "$dir"
|
||||
if git show-ref --verify --quiet "refs/heads/$branch_name" 2>/dev/null; then
|
||||
clone_dir="$dir"
|
||||
break
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
if [[ -z "$clone_dir" ]]; then
|
||||
error "Branch $branch_name not found in any clone"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd "$clone_dir"
|
||||
|
||||
log "📋 PR Simulation: $branch_name → develop"
|
||||
|
||||
# Show PR summary
|
||||
echo ""
|
||||
echo "📝 PR Summary:"
|
||||
git log --oneline "develop..$branch_name" 2>/dev/null || git log --oneline "master..$branch_name"
|
||||
|
||||
echo ""
|
||||
echo "📊 Changed files:"
|
||||
git diff --name-status "develop..$branch_name" 2>/dev/null || git diff --name-status "master..$branch_name"
|
||||
|
||||
# Run PR validation
|
||||
log "🔍 Running PR validation..."
|
||||
git checkout "$branch_name"
|
||||
|
||||
# Simulate CI for PR
|
||||
if [[ -f "../../../Makefile" ]]; then
|
||||
log "Running CI pipeline..."
|
||||
make -C "../../.." ci-dev 2>/dev/null || warn "CI validation had issues"
|
||||
fi
|
||||
|
||||
# Check for conflicts
|
||||
log "🔀 Checking for merge conflicts..."
|
||||
local target_branch="develop"
|
||||
if ! git show-ref --verify --quiet "refs/heads/$target_branch" 2>/dev/null; then
|
||||
target_branch="master"
|
||||
fi
|
||||
|
||||
if git merge-tree "$(git merge-base "$target_branch" "$branch_name")" "$target_branch" "$branch_name" | grep -q "<<<<<<< "; then
|
||||
warn "⚠️ Merge conflicts detected"
|
||||
echo "Conflicts would need resolution before merge"
|
||||
else
|
||||
log "✅ No merge conflicts detected"
|
||||
fi
|
||||
|
||||
log "📋 PR Status: Ready for review and merge"
|
||||
log "💡 To merge: $0 merge-pr $branch_name $target_branch"
|
||||
}
|
||||
|
||||
# Simulate merge conflicts
|
||||
simulate_conflict() {
|
||||
log "Simulating merge conflict scenario..."
|
||||
|
||||
# Create two conflicting branches
|
||||
local dev1_clone="$LOCAL_SERVER_DIR/clones/dev1"
|
||||
local dev2_clone="$LOCAL_SERVER_DIR/clones/dev2"
|
||||
|
||||
# Ensure clones exist
|
||||
[[ ! -d "$dev1_clone" ]] && clone_fresh "dev1"
|
||||
[[ ! -d "$dev2_clone" ]] && clone_fresh "dev2"
|
||||
|
||||
# Dev1 makes changes
|
||||
cd "$dev1_clone"
|
||||
git checkout develop 2>/dev/null || git checkout master
|
||||
git pull origin "$(git branch --show-current)"
|
||||
git checkout -b "feature/dev1-conflict"
|
||||
|
||||
echo "// Configuration by dev1" > shared-config.go
|
||||
echo "const DefaultValue = 100" >> shared-config.go
|
||||
git add shared-config.go
|
||||
git commit -m "feat(config): set default value to 100"
|
||||
git push origin "feature/dev1-conflict"
|
||||
|
||||
# Dev2 makes conflicting changes
|
||||
cd "$dev2_clone"
|
||||
git checkout develop 2>/dev/null || git checkout master
|
||||
git pull origin "$(git branch --show-current)"
|
||||
git checkout -b "feature/dev2-conflict"
|
||||
|
||||
echo "// Configuration by dev2" > shared-config.go
|
||||
echo "const DefaultValue = 200" >> shared-config.go
|
||||
git add shared-config.go
|
||||
git commit -m "feat(config): set default value to 200"
|
||||
git push origin "feature/dev2-conflict"
|
||||
|
||||
log "✅ Conflict scenario created"
|
||||
log "🔀 Two branches with conflicting changes:"
|
||||
log " - feature/dev1-conflict (sets value to 100)"
|
||||
log " - feature/dev2-conflict (sets value to 200)"
|
||||
log "💡 Try merging one into develop to see conflict resolution"
|
||||
}
|
||||
|
||||
# Push all branches to local server
|
||||
push_all() {
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
if ! git remote get-url local-server >/dev/null 2>&1; then
|
||||
error "local-server remote not configured"
|
||||
echo "Run: $0 init"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "Pushing all branches to local server..."
|
||||
git push local-server --all
|
||||
git push local-server --tags
|
||||
|
||||
log "✅ All branches and tags pushed to local server"
|
||||
}
|
||||
|
||||
# Clean server data
|
||||
clean_server() {
|
||||
warn "This will remove all local server data"
|
||||
read -p "Continue? (y/N): " -n 1 -r
|
||||
echo
|
||||
if [[ ! $REPLY =~ ^[Yy]$ ]]; then
|
||||
echo "Cancelled"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
log "Cleaning local git server data..."
|
||||
|
||||
# Remove server directory
|
||||
if [[ -d "$LOCAL_SERVER_DIR" ]]; then
|
||||
rm -rf "$LOCAL_SERVER_DIR"
|
||||
log "✅ Server data removed"
|
||||
fi
|
||||
|
||||
# Remove local-server remote from main repo
|
||||
cd "$PROJECT_ROOT"
|
||||
if git remote get-url local-server >/dev/null 2>&1; then
|
||||
git remote remove local-server
|
||||
log "✅ local-server remote removed"
|
||||
fi
|
||||
|
||||
log "🧹 Cleanup completed"
|
||||
}
|
||||
|
||||
# Main command dispatcher
|
||||
main() {
|
||||
if [[ $# -eq 0 ]]; then
|
||||
usage
|
||||
exit 0
|
||||
fi
|
||||
|
||||
local command="$1"
|
||||
shift
|
||||
|
||||
case "$command" in
|
||||
init)
|
||||
init_server
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
clone-fresh)
|
||||
clone_fresh "$@"
|
||||
;;
|
||||
simulate-dev)
|
||||
simulate_dev "$@"
|
||||
;;
|
||||
simulate-pr)
|
||||
simulate_pr "$@"
|
||||
;;
|
||||
simulate-conflict)
|
||||
simulate_conflict
|
||||
;;
|
||||
push-all)
|
||||
push_all
|
||||
;;
|
||||
clean)
|
||||
clean_server
|
||||
;;
|
||||
*)
|
||||
error "Unknown command: $command"
|
||||
usage
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
139
scripts/mev-tools.sh
Executable file
139
scripts/mev-tools.sh
Executable file
@@ -0,0 +1,139 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Global MEV Tools Manager
|
||||
# This script provides tools to manage development environments across multiple projects
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
GLOBAL_CONFIG_DIR="$HOME/.config/mev-tools"
|
||||
|
||||
# Create global config directory
|
||||
mkdir -p "$GLOBAL_CONFIG_DIR"
|
||||
|
||||
# Function to display usage
|
||||
usage() {
|
||||
echo "Usage: $0 [COMMAND]"
|
||||
echo "Global tools for MEV development"
|
||||
echo ""
|
||||
echo "Commands:"
|
||||
echo " install - Install global tools to PATH"
|
||||
echo " setup-project - Setup a new project with standardized structure"
|
||||
echo " update-tools - Update all global tools"
|
||||
echo " check-env - Check if development environment is properly configured"
|
||||
echo " help - Show this help"
|
||||
echo ""
|
||||
echo "Examples:"
|
||||
echo " $0 install # Install tools to local bin"
|
||||
echo " $0 setup-project my-project # Create new project"
|
||||
}
|
||||
|
||||
# Function to install global tools
|
||||
install_tools() {
|
||||
echo "Installing global tools..."
|
||||
|
||||
# Create local bin directory
|
||||
mkdir -p "$HOME/bin"
|
||||
|
||||
# Copy tools to bin (this script and others)
|
||||
cp "$SCRIPT_DIR/../../scripts/test-runner.sh" "$HOME/bin/test-runner" 2>/dev/null || echo "test-runner not found in expected location"
|
||||
cp "$SCRIPT_DIR/../../scripts/build.sh" "$HOME/bin/build-tool" 2>/dev/null || echo "build-tool not found in expected location"
|
||||
cp "$SCRIPT_DIR/../../scripts/setup-dev.sh" "$HOME/bin/dev-setup" 2>/dev/null || echo "dev-setup not found in expected location"
|
||||
cp "$SCRIPT_DIR/../../scripts/performance-profile.sh" "$HOME/bin/perf-profile" 2>/dev/null || echo "perf-profile not found in expected location"
|
||||
|
||||
# Make them executable
|
||||
chmod +x "$HOME/bin/test-runner" "$HOME/bin/build-tool" "$HOME/bin/dev-setup" "$HOME/bin/perf-profile" 2>/dev/null || true
|
||||
|
||||
# Add to PATH if not already there
|
||||
if [[ ":$PATH:" != *":$HOME/bin:"* ]]; then
|
||||
echo "Adding $HOME/bin to PATH..."
|
||||
echo 'export PATH="$HOME/bin:$PATH"' >> "$HOME/.bashrc"
|
||||
echo "Please run 'source ~/.bashrc' or restart your shell to update PATH"
|
||||
fi
|
||||
|
||||
echo "Tools installed successfully!"
|
||||
echo "Available tools:"
|
||||
echo " test-runner - Universal test runner"
|
||||
echo " build-tool - Universal build tool"
|
||||
echo " dev-setup - Development environment setup"
|
||||
echo " perf-profile - Performance profiling tool"
|
||||
}
|
||||
|
||||
# Function to setup a new project
|
||||
setup_project() {
|
||||
PROJECT_NAME="${1:-}"
|
||||
if [ -z "$PROJECT_NAME" ]; then
|
||||
echo "Usage: $0 setup-project <project-name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Creating new project: $PROJECT_NAME"
|
||||
"$SCRIPT_DIR/../../scripts/create-project-template.sh" "$PROJECT_NAME"
|
||||
}
|
||||
|
||||
# Function to update tools
|
||||
update_tools() {
|
||||
echo "Updating global tools..."
|
||||
echo "Note: In a real implementation, this would update tools from a central repository."
|
||||
echo "For now, please manually update the scripts."
|
||||
}
|
||||
|
||||
# Function to check environment
|
||||
check_env() {
|
||||
echo "Checking development environment..."
|
||||
|
||||
# Check Go
|
||||
if command -v go &> /dev/null; then
|
||||
echo "✓ Go $(go version | cut -d' ' -f3) installed"
|
||||
else
|
||||
echo "✗ Go not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Git
|
||||
if command -v git &> /dev/null; then
|
||||
echo "✓ Git $(git --version | cut -d' ' -f3) installed"
|
||||
else
|
||||
echo "✗ Git not installed"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check for global tools
|
||||
if command -v test-runner &> /dev/null; then
|
||||
echo "✓ test-runner available in PATH"
|
||||
else
|
||||
echo "⚠ test-runner not available in PATH"
|
||||
fi
|
||||
|
||||
if command -v build-tool &> /dev/null; then
|
||||
echo "✓ build-tool available in PATH"
|
||||
else
|
||||
echo "⚠ build-tool not available in PATH"
|
||||
fi
|
||||
|
||||
echo "Environment check completed."
|
||||
}
|
||||
|
||||
# Main command router
|
||||
case "${1:-}" in
|
||||
"install")
|
||||
install_tools
|
||||
;;
|
||||
"setup-project")
|
||||
setup_project "$2"
|
||||
;;
|
||||
"update-tools")
|
||||
update_tools
|
||||
;;
|
||||
"check-env")
|
||||
check_env
|
||||
;;
|
||||
"help"|"-h"|"--help")
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
usage
|
||||
if [ $# -gt 0 ]; then
|
||||
exit 1
|
||||
fi
|
||||
;;
|
||||
esac
|
||||
46
scripts/performance-profile.sh
Executable file
46
scripts/performance-profile.sh
Executable file
@@ -0,0 +1,46 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Performance profiling script
|
||||
|
||||
# Set default values
|
||||
REPORT_DIR="${REPORT_DIR:-reports/performance}"
|
||||
BINARY_DIR="${BINARY_DIR:-bin}"
|
||||
BINARY_NAME="${BINARY_NAME:-mev-bot}"
|
||||
PROFILE_TYPES="${PROFILE_TYPES:-cpu,mem,block,mutex}"
|
||||
TIMEOUT="${TIMEOUT:-30s}"
|
||||
|
||||
echo "Starting performance profile..."
|
||||
|
||||
# Create report directory
|
||||
mkdir -p "$REPORT_DIR"
|
||||
|
||||
# Build the application if it doesn't exist
|
||||
if [ ! -f "$BINARY_DIR/$BINARY_NAME" ]; then
|
||||
echo "Building application..."
|
||||
make build
|
||||
fi
|
||||
|
||||
# Run the application with profiling enabled
|
||||
echo "Running application with profiling for $TIMEOUT..."
|
||||
"$BINARY_DIR/$BINARY_NAME" --config config/development.yaml &
|
||||
APP_PID=$!
|
||||
|
||||
# Wait for the app to start
|
||||
sleep 2
|
||||
|
||||
# Profile the application
|
||||
if command -v go &> /dev/null; then
|
||||
# Use go tool pprof to profile the running application
|
||||
echo "Profiling CPU for $TIMEOUT..."
|
||||
go tool pprof -text -top -nodecount=10 "http://localhost:6060/debug/pprof/profile?seconds=${TIMEOUT%?}" > "$REPORT_DIR/cpu-profile.txt" 2>/dev/null || echo "Could not connect to pprof endpoint, make sure your app has debug/pprof enabled"
|
||||
|
||||
echo "Profiling memory..."
|
||||
go tool pprof -text -top -nodecount=10 "http://localhost:6060/debug/pprof/heap" > "$REPORT_DIR/mem-profile.txt" 2>/dev/null || echo "Could not connect to heap profile endpoint"
|
||||
fi
|
||||
|
||||
# Alternative: run a benchmark test if the application doesn't support pprof
|
||||
echo "Running benchmark tests..."
|
||||
go test -bench=. -benchmem -run=^$ ./pkg/... ./cmd/... > "$REPORT_DIR/benchmark-results.txt"
|
||||
|
||||
echo "Performance profiling complete. Reports saved to $REPORT_DIR"
|
||||
312
scripts/production-start.sh
Executable file
312
scripts/production-start.sh
Executable file
@@ -0,0 +1,312 @@
|
||||
#!/usr/bin/env bash
|
||||
# 🚀 MEV BOT PRODUCTION STARTUP SCRIPT - IMMEDIATE PROFIT MODE
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
|
||||
cd "$PROJECT_ROOT"
|
||||
|
||||
# Colors
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
BLUE='\033[0;34m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m'
|
||||
|
||||
log() {
|
||||
echo -e "${GREEN}[PRODUCTION-START]${NC} $*"
|
||||
}
|
||||
|
||||
warn() {
|
||||
echo -e "${YELLOW}[WARNING]${NC} $*"
|
||||
}
|
||||
|
||||
error() {
|
||||
echo -e "${RED}[ERROR]${NC} $*"
|
||||
}
|
||||
|
||||
info() {
|
||||
echo -e "${BLUE}[INFO]${NC} $*"
|
||||
}
|
||||
|
||||
header() {
|
||||
echo -e "${BOLD}${GREEN}===============================================${NC}"
|
||||
echo -e "${BOLD}${GREEN} 🚀 MEV BOT PRODUCTION DEPLOYMENT - PROFIT MODE${NC}"
|
||||
echo -e "${BOLD}${GREEN}===============================================${NC}"
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Pre-flight checks
|
||||
preflight_checks() {
|
||||
log "Running pre-flight checks..."
|
||||
|
||||
# Check if binary exists and is recent
|
||||
if [[ ! -f "bin/mev-bot" ]]; then
|
||||
error "MEV bot binary not found. Building..."
|
||||
make build
|
||||
fi
|
||||
|
||||
# Check if binary is executable
|
||||
if [[ ! -x "bin/mev-bot" ]]; then
|
||||
chmod +x bin/mev-bot
|
||||
fi
|
||||
|
||||
# Verify binary
|
||||
local binary_info
|
||||
binary_info=$(file bin/mev-bot)
|
||||
if [[ "$binary_info" =~ "ELF 64-bit" ]]; then
|
||||
log "✅ Binary verified: $(ls -lh bin/mev-bot | awk '{print $5}')"
|
||||
else
|
||||
error "❌ Invalid binary format"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check Go version
|
||||
local go_version
|
||||
go_version=$(go version | grep -o 'go[0-9.]*' | head -1)
|
||||
log "✅ Go version: $go_version"
|
||||
|
||||
# Check critical directories
|
||||
mkdir -p keystore/production logs backups/production
|
||||
log "✅ Production directories created"
|
||||
|
||||
# Check environment file
|
||||
if [[ -f ".env.production.secure" ]]; then
|
||||
log "✅ Production environment configuration found"
|
||||
else
|
||||
warn "Production environment not configured"
|
||||
return 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Validate configuration
|
||||
validate_config() {
|
||||
log "Validating production configuration..."
|
||||
|
||||
# Source production environment
|
||||
if [[ -f ".env.production.secure" ]]; then
|
||||
source .env.production.secure
|
||||
else
|
||||
error "Production environment file not found"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Validate critical settings
|
||||
if [[ -z "${MEV_BOT_ENCRYPTION_KEY:-}" ]]; then
|
||||
error "MEV_BOT_ENCRYPTION_KEY not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ ${#MEV_BOT_ENCRYPTION_KEY} -lt 32 ]]; then
|
||||
error "MEV_BOT_ENCRYPTION_KEY too short (minimum 32 characters)"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -z "${ARBITRUM_RPC_ENDPOINT:-}" ]]; then
|
||||
error "ARBITRUM_RPC_ENDPOINT not set"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
log "✅ Configuration validated"
|
||||
}
|
||||
|
||||
# Start monitoring
|
||||
start_monitoring() {
|
||||
log "Starting monitoring and metrics..."
|
||||
|
||||
# Start Prometheus (if available)
|
||||
if command -v prometheus >/dev/null 2>&1; then
|
||||
log "Starting Prometheus..."
|
||||
prometheus --config.file=monitoring/prometheus.yml --storage.tsdb.path=monitoring/data &
|
||||
echo $! > monitoring/prometheus.pid
|
||||
fi
|
||||
|
||||
# Start Grafana (if available)
|
||||
if command -v grafana-server >/dev/null 2>&1; then
|
||||
log "Starting Grafana..."
|
||||
grafana-server --config=monitoring/grafana.ini &
|
||||
echo $! > monitoring/grafana.pid
|
||||
fi
|
||||
|
||||
log "✅ Monitoring started (check ports 9090, 3000)"
|
||||
}
|
||||
|
||||
# Start MEV bot
|
||||
start_mev_bot() {
|
||||
log "🚀 Starting MEV Bot in PRODUCTION mode..."
|
||||
|
||||
# Set production environment
|
||||
export $(cat .env.production.secure | grep -v '^#' | xargs)
|
||||
|
||||
# Additional production environment
|
||||
export GO_ENV=production
|
||||
export DEBUG=false
|
||||
export LOG_LEVEL=info
|
||||
|
||||
# Performance tuning
|
||||
export GOMAXPROCS=4
|
||||
export GOGC=100
|
||||
|
||||
# Start the bot with proper logging
|
||||
log "Starting MEV bot process..."
|
||||
|
||||
# Create log file with timestamp
|
||||
local log_file="logs/production-$(date +%Y%m%d-%H%M%S).log"
|
||||
|
||||
# Start bot with output to both console and log file
|
||||
./bin/mev-bot start 2>&1 | tee "$log_file" &
|
||||
|
||||
local bot_pid=$!
|
||||
echo "$bot_pid" > mev-bot.pid
|
||||
|
||||
log "✅ MEV Bot started with PID: $bot_pid"
|
||||
log "📊 Logs: $log_file"
|
||||
log "🔍 Monitor with: tail -f $log_file"
|
||||
|
||||
# Wait a moment to check if process started successfully
|
||||
sleep 3
|
||||
|
||||
if kill -0 "$bot_pid" 2>/dev/null; then
|
||||
log "🎉 MEV Bot is running successfully!"
|
||||
log "💰 Profit tracking active - monitor logs for opportunities"
|
||||
else
|
||||
error "❌ MEV Bot failed to start"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Display status
|
||||
show_status() {
|
||||
echo ""
|
||||
log "🎯 PRODUCTION STATUS:"
|
||||
echo ""
|
||||
|
||||
# MEV Bot status
|
||||
if [[ -f "mev-bot.pid" ]]; then
|
||||
local bot_pid
|
||||
bot_pid=$(cat mev-bot.pid)
|
||||
if kill -0 "$bot_pid" 2>/dev/null; then
|
||||
info "✅ MEV Bot: RUNNING (PID: $bot_pid)"
|
||||
else
|
||||
warn "❌ MEV Bot: STOPPED"
|
||||
fi
|
||||
else
|
||||
warn "❌ MEV Bot: NOT STARTED"
|
||||
fi
|
||||
|
||||
# Monitoring status
|
||||
if [[ -f "monitoring/prometheus.pid" ]]; then
|
||||
local prom_pid
|
||||
prom_pid=$(cat monitoring/prometheus.pid)
|
||||
if kill -0 "$prom_pid" 2>/dev/null; then
|
||||
info "✅ Prometheus: RUNNING (PID: $prom_pid) - http://localhost:9090"
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ -f "monitoring/grafana.pid" ]]; then
|
||||
local grafana_pid
|
||||
grafana_pid=$(cat monitoring/grafana.pid)
|
||||
if kill -0 "$grafana_pid" 2>/dev/null; then
|
||||
info "✅ Grafana: RUNNING (PID: $grafana_pid) - http://localhost:3000"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo ""
|
||||
log "💡 Quick Commands:"
|
||||
log " View logs: tail -f logs/production-*.log"
|
||||
log " Stop bot: ./scripts/production-stop.sh"
|
||||
log " Monitor: watch -n 1 'ps aux | grep mev-bot'"
|
||||
echo ""
|
||||
|
||||
log "🎯 READY FOR PROFIT GENERATION!"
|
||||
log "Monitor the logs for arbitrage opportunities and executed trades"
|
||||
}
|
||||
|
||||
# Production safety warning
|
||||
safety_warning() {
|
||||
echo ""
|
||||
warn "⚠️ PRODUCTION DEPLOYMENT WARNING:"
|
||||
echo ""
|
||||
echo "1. 💰 This will start LIVE trading with real funds"
|
||||
echo "2. 🔑 Ensure your private keys are secure"
|
||||
echo "3. 💸 Start with small position sizes"
|
||||
echo "4. 📊 Monitor all transactions closely"
|
||||
echo "5. 🚨 Set up alerts for unusual activity"
|
||||
echo ""
|
||||
|
||||
read -p "Are you ready to start LIVE trading? (type 'PROFIT' to confirm): " -r
|
||||
if [[ $REPLY != "PROFIT" ]]; then
|
||||
echo "Deployment cancelled"
|
||||
exit 0
|
||||
fi
|
||||
echo ""
|
||||
}
|
||||
|
||||
# Quick deployment mode
|
||||
quick_deploy() {
|
||||
log "🚀 QUICK DEPLOYMENT MODE - MAXIMUM SPEED TO PROFIT"
|
||||
|
||||
# Skip most checks, assume environment is ready
|
||||
export $(cat .env.production.secure | grep -v '^#' | xargs)
|
||||
export GO_ENV=production
|
||||
export DEBUG=false
|
||||
|
||||
# Start bot immediately
|
||||
./bin/mev-bot start &
|
||||
local bot_pid=$!
|
||||
echo "$bot_pid" > mev-bot.pid
|
||||
|
||||
log "⚡ MEV Bot deployed in QUICK mode (PID: $bot_pid)"
|
||||
log "💰 PROFIT GENERATION ACTIVE"
|
||||
|
||||
# Quick status check
|
||||
sleep 2
|
||||
if kill -0 "$bot_pid" 2>/dev/null; then
|
||||
log "🎉 SUCCESS - Bot is generating profits!"
|
||||
else
|
||||
error "❌ Quick deployment failed"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Main deployment function
|
||||
main() {
|
||||
local mode="${1:-full}"
|
||||
|
||||
header
|
||||
|
||||
case "$mode" in
|
||||
quick)
|
||||
log "QUICK DEPLOYMENT MODE"
|
||||
quick_deploy
|
||||
;;
|
||||
full)
|
||||
log "FULL PRODUCTION DEPLOYMENT"
|
||||
safety_warning
|
||||
preflight_checks
|
||||
validate_config
|
||||
start_monitoring
|
||||
start_mev_bot
|
||||
show_status
|
||||
;;
|
||||
status)
|
||||
show_status
|
||||
;;
|
||||
*)
|
||||
error "Unknown mode: $mode"
|
||||
echo "Usage: $0 [full|quick|status]"
|
||||
echo " full - Complete production deployment with all checks"
|
||||
echo " quick - Fast deployment, skip checks (IMMEDIATE PROFIT)"
|
||||
echo " status - Show current status"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
# Handle interrupts gracefully
|
||||
trap 'error "Deployment interrupted"; exit 1' INT TERM
|
||||
|
||||
# Run main function
|
||||
main "$@"
|
||||
@@ -8,6 +8,12 @@ echo "Running MEV bot..."
|
||||
./scripts/build.sh
|
||||
|
||||
if [ $? -eq 0 ]; then
|
||||
# Normalize GO_ENV when passed as .env.* style
|
||||
if [[ -n "$GO_ENV" && "$GO_ENV" == .env.* ]]; then
|
||||
GO_ENV="${GO_ENV#.env.}"
|
||||
export GO_ENV
|
||||
fi
|
||||
|
||||
# Load environment variables from .env.production if it exists
|
||||
if [ -f ".env.production" ]; then
|
||||
echo "🔧 Loading production environment variables from .env.production..."
|
||||
@@ -34,10 +40,21 @@ if [ $? -eq 0 ]; then
|
||||
fi
|
||||
|
||||
# Set required environment variables with production values
|
||||
export ARBITRUM_RPC_ENDPOINT="${ARBITRUM_RPC_ENDPOINT:-wss://arbitrum-mainnet.core.chainstack.com/f69d14406bc00700da9b936504e1a870}"
|
||||
export ARBITRUM_RPC_ENDPOINT="${ARBITRUM_RPC_ENDPOINT:-wss://arbitrum-mainnet.core.chainstack.com/53c30e7a941160679fdcc396c894fc57}"
|
||||
export ARBITRUM_WS_ENDPOINT="${ARBITRUM_WS_ENDPOINT:-$ARBITRUM_RPC_ENDPOINT}"
|
||||
export METRICS_ENABLED="${METRICS_ENABLED:-true}"
|
||||
export METRICS_PORT="${METRICS_PORT:-9090}"
|
||||
|
||||
export MEV_BOT_KEYSTORE_PATH="${MEV_BOT_KEYSTORE_PATH:-keystore/production}"
|
||||
export MEV_BOT_AUDIT_LOG="${MEV_BOT_AUDIT_LOG:-logs/production_audit.log}"
|
||||
export MEV_BOT_BACKUP_PATH="${MEV_BOT_BACKUP_PATH:-backups/production}"
|
||||
|
||||
mkdir -p "$MEV_BOT_KEYSTORE_PATH"
|
||||
mkdir -p "$MEV_BOT_BACKUP_PATH"
|
||||
mkdir -p "$(dirname "$MEV_BOT_AUDIT_LOG")"
|
||||
|
||||
echo "Keystore path: $MEV_BOT_KEYSTORE_PATH"
|
||||
env | grep MEV_BOT_KEYSTORE_PATH
|
||||
|
||||
echo ""
|
||||
echo "🚀 PRODUCTION MEV BOT STARTUP"
|
||||
@@ -61,4 +78,4 @@ if [ $? -eq 0 ]; then
|
||||
else
|
||||
echo "Failed to build the application!"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
10
scripts/run_audit_suite.sh
Executable file
10
scripts/run_audit_suite.sh
Executable file
@@ -0,0 +1,10 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REPORT_DIR="${1:-$ROOT_DIR/reports/math/latest}"
|
||||
|
||||
echo "Running math audit using vectors: default"
|
||||
GOCACHE="${GOCACHE:-$ROOT_DIR/.gocache}" \
|
||||
GOFLAGS="${GOFLAGS:-}" \
|
||||
go run ./tools/math-audit --vectors default --report "${REPORT_DIR}"
|
||||
14
scripts/run_profit_simulation.sh
Executable file
14
scripts/run_profit_simulation.sh
Executable file
@@ -0,0 +1,14 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
||||
REPORT_DIR="${1:-$ROOT_DIR/reports/simulation/latest}"
|
||||
VECTORS="${SIMULATION_VECTORS:-$ROOT_DIR/tools/simulation/vectors/default.json}"
|
||||
|
||||
mkdir -p "$REPORT_DIR"
|
||||
|
||||
GOCACHE="${GOCACHE:-$ROOT_DIR/.gocache}" \
|
||||
GOFLAGS="${GOFLAGS:-}" \
|
||||
go run ./tools/simulation --vectors "$VECTORS" --report "$REPORT_DIR"
|
||||
|
||||
echo "Simulation summary written to $REPORT_DIR"
|
||||
@@ -105,7 +105,7 @@ echo "4. Configuration Security"
|
||||
echo "========================"
|
||||
|
||||
run_check "Secure Config" "test -f pkg/security/config.go" "Check if secure configuration is implemented"
|
||||
run_check "No Hardcoded Endpoints" "! grep -r 'wss://.*chainstack.*f69d14406bc00700da9b936504e1a870' pkg/ --include='*.go'" "Check that hardcoded endpoints are removed"
|
||||
run_check "No Hardcoded Endpoints" "! grep -r 'wss://.*chainstack.*53c30e7a941160679fdcc396c894fc57' pkg/ --include='*.go'" "Check that hardcoded endpoints are removed"
|
||||
|
||||
# Check configuration validation
|
||||
if [ -f pkg/security/config.go ]; then
|
||||
|
||||
62
scripts/setup-dev.sh
Executable file
62
scripts/setup-dev.sh
Executable file
@@ -0,0 +1,62 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Development environment setup script
|
||||
|
||||
echo "Setting up development environment..."
|
||||
|
||||
# Create directories if they don't exist
|
||||
mkdir -p logs
|
||||
mkdir -p reports
|
||||
mkdir -p reports/coverage
|
||||
mkdir -p reports/test-results
|
||||
mkdir -p reports/augments
|
||||
mkdir -p storage
|
||||
mkdir -p storage/keystore
|
||||
mkdir -p storage/cache
|
||||
mkdir -p .gocache
|
||||
|
||||
# Check if Go is installed
|
||||
if ! command -v go &> /dev/null; then
|
||||
echo "Error: Go is not installed" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Check if required tools are installed
|
||||
echo "Checking for required tools..."
|
||||
|
||||
# Install golangci-lint if not present
|
||||
if ! command -v golangci-lint &> /dev/null; then
|
||||
echo "Installing golangci-lint..."
|
||||
go install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
|
||||
fi
|
||||
|
||||
# Install gosec if not present
|
||||
if ! command -v gosec &> /dev/null; then
|
||||
echo "Installing gosec..."
|
||||
go install github.com/securego/gosec/v2/cmd/gosec@latest
|
||||
fi
|
||||
|
||||
# Install govulncheck if not present
|
||||
if ! command -v govulncheck &> /dev/null; then
|
||||
echo "Installing govulncheck..."
|
||||
go install golang.org/x/vuln/cmd/govulncheck@latest
|
||||
fi
|
||||
|
||||
# Install delve if not present
|
||||
if ! command -v dlv &> /dev/null; then
|
||||
echo "Installing delve..."
|
||||
go install github.com/go-delve/delve/cmd/dlv@latest
|
||||
fi
|
||||
|
||||
# Copy example config if not exists
|
||||
if [ ! -f config/development.yaml ]; then
|
||||
echo "Creating development config..."
|
||||
cp config/development.yaml.example config/development.yaml 2>/dev/null || echo "Config example not found, creating basic config..."
|
||||
fi
|
||||
|
||||
# Verify Go modules
|
||||
echo "Verifying Go modules..."
|
||||
go mod tidy
|
||||
|
||||
echo "Development environment setup complete!"
|
||||
179
scripts/staging-pipeline-local.sh
Executable file
179
scripts/staging-pipeline-local.sh
Executable file
@@ -0,0 +1,179 @@
|
||||
#!/usr/bin/env bash
|
||||
|
||||
set -euo pipefail
|
||||
|
||||
ROOT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
LOG_DIR="${LOCAL_STAGING_LOG_DIR:-$ROOT_DIR/reports/ci/local-staging}"
|
||||
mkdir -p "$LOG_DIR"
|
||||
|
||||
export GOCACHE="${LOCAL_STAGING_GOCACHE:-$ROOT_DIR/.gocache}"
|
||||
export GOMODCACHE="${LOCAL_STAGING_GOMODCACHE:-$ROOT_DIR/.gomodcache}"
|
||||
mkdir -p "$GOCACHE" "$GOMODCACHE"
|
||||
|
||||
BRANCH="${LOCAL_STAGING_BRANCH:-$(git rev-parse --abbrev-ref HEAD)}"
|
||||
GO_IMAGE="${LOCAL_STAGING_GO_IMAGE:-docker.io/library/golang:1.24}"
|
||||
GOLANGCI_IMAGE="${LOCAL_STAGING_GOLANGCI_IMAGE:-docker.io/golangci/golangci-lint:v1.60.1}"
|
||||
HELM_IMAGE="${LOCAL_STAGING_HELM_IMAGE:-docker.io/alpine/helm:3.15.2}"
|
||||
KUBECTL_IMAGE="${LOCAL_STAGING_KUBECTL_IMAGE:-docker.io/bitnami/kubectl:1.30.1}"
|
||||
|
||||
IMAGE_NAME="${LOCAL_STAGING_IMAGE_NAME:-mev-bot}"
|
||||
IMAGE_TAG="${LOCAL_STAGING_IMAGE_TAG:-staging-local}"
|
||||
IMAGE_REF="${IMAGE_NAME}:${IMAGE_TAG}"
|
||||
IMAGE_TAR="${LOCAL_STAGING_IMAGE_TAR:-$ROOT_DIR/${IMAGE_NAME}-${IMAGE_TAG}.tar}"
|
||||
|
||||
HELM_RELEASE="${LOCAL_STAGING_HELM_RELEASE:-mev-bot}"
|
||||
HELM_NAMESPACE="${LOCAL_STAGING_HELM_NAMESPACE:-mev-bot-staging}"
|
||||
HELM_CHART="${LOCAL_STAGING_HELM_CHART:-charts/mev-bot}"
|
||||
HELM_DRY_RUN="${LOCAL_STAGING_HELM_DRY_RUN:-true}"
|
||||
KUBECONFIG_PATH="${LOCAL_STAGING_KUBECONFIG:-$HOME/.kube/config}"
|
||||
|
||||
SKIP_DOCKER="${LOCAL_STAGING_SKIP_DOCKER:-false}"
|
||||
SKIP_DEPLOY="${LOCAL_STAGING_SKIP_DEPLOY:-false}"
|
||||
|
||||
CONTAINER_RUNTIME="${LOCAL_STAGING_RUNTIME:-}"
|
||||
if [[ -z "$CONTAINER_RUNTIME" ]]; then
|
||||
if command -v podman >/dev/null 2>&1; then
|
||||
CONTAINER_RUNTIME=podman
|
||||
elif command -v docker >/dev/null 2>&1; then
|
||||
CONTAINER_RUNTIME=docker
|
||||
else
|
||||
echo "ERROR: Neither podman nor docker is available. Install one or set LOCAL_STAGING_RUNTIME." >&2
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
if ! command -v "$CONTAINER_RUNTIME" >/dev/null 2>&1; then
|
||||
echo "ERROR: Container runtime '$CONTAINER_RUNTIME' not found in PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
|
||||
CONTAINER_CMD=("$CONTAINER_RUNTIME")
|
||||
if [[ "$CONTAINER_RUNTIME" == "podman" ]]; then
|
||||
CONTAINER_CMD+=("--remote")
|
||||
fi
|
||||
|
||||
CONTAINER_USER="$(id -u):$(id -g)"
|
||||
RUNTIME_ARGS=(-u "$CONTAINER_USER" -v "$ROOT_DIR":/work -w /work -v "$GOCACHE":/gocache -v "$GOMODCACHE":/gomodcache -e GOCACHE=/gocache -e GOMODCACHE=/gomodcache)
|
||||
if [[ "$CONTAINER_RUNTIME" == "podman" ]]; then
|
||||
RUNTIME_ARGS+=(--security-opt label=disable)
|
||||
fi
|
||||
|
||||
run_step() {
|
||||
local name="$1"
|
||||
shift
|
||||
local logfile="$LOG_DIR/${name}.log"
|
||||
printf '[%s] Starting %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$name"
|
||||
if "$@" |& tee "$logfile"; then
|
||||
printf '[%s] Completed %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$name"
|
||||
else
|
||||
printf '[%s] Failed %s; see %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$name" "$logfile"
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
log() {
|
||||
printf '[%s] %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*"
|
||||
}
|
||||
|
||||
require_cmd() {
|
||||
if ! command -v "$1" >/dev/null 2>&1; then
|
||||
echo "ERROR: Required command '$1' not found" >&2
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
run_container_step() {
|
||||
local step="$1"
|
||||
local image="$2"
|
||||
shift 2
|
||||
local cmd="$*"
|
||||
run_step "$step" "${CONTAINER_CMD[@]}" run --rm "${RUNTIME_ARGS[@]}" "$image" bash -lc "$cmd"
|
||||
}
|
||||
|
||||
run_container_step_env() {
|
||||
local step="$1"
|
||||
local image="$2"
|
||||
shift 2
|
||||
local env_args=()
|
||||
while [[ $# -gt 0 && "$1" == --env=* ]]; do
|
||||
env_args+=("${1/--env=/}")
|
||||
shift
|
||||
done
|
||||
local cmd="$*"
|
||||
local run_args=("${RUNTIME_ARGS[@]}")
|
||||
for env in "${env_args[@]}"; do
|
||||
run_args+=(-e "$env")
|
||||
done
|
||||
run_step "$step" "${CONTAINER_CMD[@]}" run --rm "${run_args[@]}" "$image" bash -lc "$cmd"
|
||||
}
|
||||
|
||||
require_cmd git
|
||||
|
||||
log "Running local staging pipeline for branch ${BRANCH} using ${CONTAINER_CMD[*]}"
|
||||
log "Logs: $LOG_DIR"
|
||||
|
||||
HOST_GOROOT="${LOCAL_STAGING_GOROOT:-}"
|
||||
if [[ -z "$HOST_GOROOT" ]] && command -v go >/dev/null 2>&1; then
|
||||
HOST_GOROOT=$(go env GOROOT 2>/dev/null || true)
|
||||
fi
|
||||
if [[ -n "$HOST_GOROOT" && -d "$HOST_GOROOT" ]]; then
|
||||
RUNTIME_ARGS+=(-v "$HOST_GOROOT":/goroot:ro -e GOROOT=/goroot)
|
||||
GO_BIN_PATH="/goroot/bin:/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
else
|
||||
GO_BIN_PATH="/usr/local/go/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
|
||||
fi
|
||||
|
||||
run_container_step_env setup-dependencies "$GO_IMAGE" "export PATH=$GO_BIN_PATH; go mod download && go mod verify"
|
||||
|
||||
run_container_step_env lint "$GOLANGCI_IMAGE" --env=GOLANGCI_LINT_CACHE=/tmp/golangci-lint --env=PATH="$GO_BIN_PATH" "golangci-lint run --timeout=10m"
|
||||
|
||||
run_container_step_env unit-tests "$GO_IMAGE" "export PATH=$GO_BIN_PATH; go test -race -coverprofile=coverage.out ./..."
|
||||
if [[ -f coverage.out ]]; then
|
||||
mv coverage.out "$LOG_DIR/coverage.out"
|
||||
fi
|
||||
|
||||
run_container_step_env math-audit "$GO_IMAGE" "export PATH=$GO_BIN_PATH; go run ./tools/math-audit --vectors default --report reports/math/latest"
|
||||
|
||||
run_container_step_env profit-simulation "$GO_IMAGE" "export PATH=$GO_BIN_PATH; ./scripts/run_profit_simulation.sh"
|
||||
|
||||
if [[ "$SKIP_DOCKER" != "true" ]]; then
|
||||
run_step docker-build "${CONTAINER_CMD[@]}" build -t "$IMAGE_REF" .
|
||||
run_step docker-save "${CONTAINER_CMD[@]}" save "$IMAGE_REF" -o "$IMAGE_TAR"
|
||||
else
|
||||
log "Skipping Docker/Podman build and save (LOCAL_STAGING_SKIP_DOCKER=true)"
|
||||
fi
|
||||
|
||||
if [[ "$SKIP_DEPLOY" != "true" ]]; then
|
||||
HELM_RUN_ARGS=("${RUNTIME_ARGS[@]}")
|
||||
if [[ -f "$KUBECONFIG_PATH" ]]; then
|
||||
HELM_RUN_ARGS+=(-v "$KUBECONFIG_PATH":/kubeconfig:ro -e KUBECONFIG=/kubeconfig)
|
||||
elif [[ "$HELM_DRY_RUN" == "false" ]]; then
|
||||
echo "ERROR: kubeconfig not found at $KUBECONFIG_PATH" >&2
|
||||
exit 1
|
||||
fi
|
||||
HELM_CMD=(helm upgrade --install "$HELM_RELEASE" "$HELM_CHART" --set "image.tag=${IMAGE_TAG}" --namespace "$HELM_NAMESPACE")
|
||||
if [[ "$HELM_DRY_RUN" != "false" ]]; then
|
||||
HELM_CMD+=('--dry-run')
|
||||
fi
|
||||
run_step helm-upgrade "${CONTAINER_CMD[@]}" run --rm "${HELM_RUN_ARGS[@]}" "$HELM_IMAGE" bash -lc "${HELM_CMD[*]}"
|
||||
|
||||
if command -v kubectl >/dev/null 2>&1 && [[ "$HELM_DRY_RUN" == "false" ]]; then
|
||||
run_step rollout-status kubectl rollout status "deploy/${HELM_RELEASE}" -n "$HELM_NAMESPACE" --timeout=120s
|
||||
run_step rollout-logs kubectl logs "deploy/${HELM_RELEASE}" -n "$HELM_NAMESPACE" --tail=100
|
||||
elif [[ "$HELM_DRY_RUN" == "false" ]]; then
|
||||
KUBE_RUN_ARGS=("${RUNTIME_ARGS[@]}")
|
||||
if [[ -f "$KUBECONFIG_PATH" ]]; then
|
||||
KUBE_RUN_ARGS+=(-v "$KUBECONFIG_PATH":/kubeconfig:ro -e KUBECONFIG=/kubeconfig)
|
||||
fi
|
||||
run_step rollout-status "${CONTAINER_CMD[@]}" run --rm "${KUBE_RUN_ARGS[@]}" "$KUBECTL_IMAGE" bash -lc "kubectl rollout status deploy/${HELM_RELEASE} -n ${HELM_NAMESPACE} --timeout=120s"
|
||||
run_step rollout-logs "${CONTAINER_CMD[@]}" run --rm "${KUBE_RUN_ARGS[@]}" "$KUBECTL_IMAGE" bash -lc "kubectl logs deploy/${HELM_RELEASE} -n ${HELM_NAMESPACE} --tail=100"
|
||||
else
|
||||
log "Skipping rollout status/log tail (dry run or kube tooling unavailable)"
|
||||
fi
|
||||
else
|
||||
log "Skipping deploy stage (LOCAL_STAGING_SKIP_DEPLOY=true)"
|
||||
fi
|
||||
|
||||
log "Local staging pipeline completed"
|
||||
@@ -19,7 +19,7 @@ pkill -f anvil || true
|
||||
sleep 2
|
||||
|
||||
# Set up environment variables for forked network
|
||||
export ARBITRUM_RPC_ENDPOINT="https://arbitrum-mainnet.core.chainstack.com/f69d14406bc00700da9b936504e1a870"
|
||||
export ARBITRUM_RPC_ENDPOINT="https://arbitrum-mainnet.core.chainstack.com/53c30e7a941160679fdcc396c894fc57"
|
||||
export ARBITRUM_WS_ENDPOINT="ws://localhost:8545"
|
||||
export METRICS_ENABLED="false"
|
||||
export MEV_BOT_ENCRYPTION_KEY="test-fork-encryption-key-32-chars"
|
||||
|
||||
130
scripts/test-runner.sh
Executable file
130
scripts/test-runner.sh
Executable file
@@ -0,0 +1,130 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Reusable, agnostic test runner script
|
||||
# Can be used in any Go project by adjusting configuration
|
||||
|
||||
# Configuration variables
|
||||
TEST_LEVEL="${TEST_LEVEL:-basic}" # basic, unit, integration, comprehensive, audit
|
||||
COVERAGE="${COVERAGE:-false}"
|
||||
OUTPUT_DIR="${OUTPUT_DIR:-test-results}"
|
||||
PACKAGE_FILTER="${PACKAGE_FILTER:-./...}"
|
||||
TIMEOUT="${TIMEOUT:-10m}"
|
||||
JUNIT_OUTPUT="${JUNIT_OUTPUT:-false}"
|
||||
|
||||
# Parse command line arguments
|
||||
while [[ $# -gt 0 ]]; do
|
||||
case $1 in
|
||||
-l|--level)
|
||||
TEST_LEVEL="$2"
|
||||
shift 2
|
||||
;;
|
||||
-c|--coverage)
|
||||
COVERAGE=true
|
||||
shift
|
||||
;;
|
||||
-o|--output)
|
||||
OUTPUT_DIR="$2"
|
||||
shift 2
|
||||
;;
|
||||
-p|--package)
|
||||
PACKAGE_FILTER="$2"
|
||||
shift 2
|
||||
;;
|
||||
--junit)
|
||||
JUNIT_OUTPUT=true
|
||||
shift
|
||||
;;
|
||||
-t|--timeout)
|
||||
TIMEOUT="$2"
|
||||
shift 2
|
||||
;;
|
||||
-h|--help)
|
||||
echo "Usage: $0 [OPTIONS]"
|
||||
echo "Run tests with different levels of coverage"
|
||||
echo ""
|
||||
echo "Options:"
|
||||
echo " -l, --level LEVEL Test level: basic, unit, integration, comprehensive, audit (default: basic)"
|
||||
echo " -c, --coverage Generate coverage report"
|
||||
echo " -o, --output DIR Output directory (default: test-results)"
|
||||
echo " -p, --package PKG Package filter (default: ./...)"
|
||||
echo " --junit Generate JUnit output"
|
||||
echo " -t, --timeout DURATION Timeout duration (default: 10m)"
|
||||
echo " -h, --help Show this help"
|
||||
exit 0
|
||||
;;
|
||||
*)
|
||||
echo "Unknown option: $1"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Starting test execution (level: $TEST_LEVEL, coverage: $COVERAGE)"
|
||||
|
||||
# Create output directory
|
||||
mkdir -p "$OUTPUT_DIR"
|
||||
|
||||
# Run tests based on level
|
||||
case $TEST_LEVEL in
|
||||
"basic")
|
||||
echo "Running basic tests..."
|
||||
if [ "$COVERAGE" = "true" ]; then
|
||||
go test -v -short -coverprofile="$OUTPUT_DIR/coverage.out" -covermode=atomic "$PACKAGE_FILTER"
|
||||
go tool cover -html="$OUTPUT_DIR/coverage.out" -o "$OUTPUT_DIR/coverage.html"
|
||||
else
|
||||
go test -v -short "$PACKAGE_FILTER"
|
||||
fi
|
||||
;;
|
||||
"unit")
|
||||
echo "Running unit tests..."
|
||||
if [ "$COVERAGE" = "true" ]; then
|
||||
go test -v ./test/unit/... -coverprofile="$OUTPUT_DIR/coverage.out" -covermode=atomic
|
||||
go tool cover -html="$OUTPUT_DIR/coverage.out" -o "$OUTPUT_DIR/coverage.html"
|
||||
else
|
||||
go test -v ./test/unit/...
|
||||
fi
|
||||
;;
|
||||
"integration")
|
||||
echo "Running integration tests..."
|
||||
if [ "$COVERAGE" = "true" ]; then
|
||||
go test -v ./test/integration/... -coverprofile="$OUTPUT_DIR/coverage.out" -covermode=atomic
|
||||
go tool cover -html="$OUTPUT_DIR/coverage.out" -o "$OUTPUT_DIR/coverage.html"
|
||||
else
|
||||
go test -v ./test/integration/...
|
||||
fi
|
||||
;;
|
||||
"comprehensive")
|
||||
echo "Running comprehensive tests..."
|
||||
if [ "$COVERAGE" = "true" ]; then
|
||||
go test -v ./test/unit/... ./test/integration/... ./test/e2e/... -coverprofile="$OUTPUT_DIR/coverage.out" -covermode=atomic
|
||||
go tool cover -html="$OUTPUT_DIR/coverage.out" -o "$OUTPUT_DIR/coverage.html"
|
||||
else
|
||||
go test -v ./test/unit/... ./test/integration/... ./test/e2e/...
|
||||
fi
|
||||
;;
|
||||
"audit")
|
||||
echo "Running audit tests..."
|
||||
if [ "$COVERAGE" = "true" ]; then
|
||||
go test -v ./test/unit/... ./test/integration/... ./test/e2e/... ./test/property/... ./test/fuzzing/... ./test/security/... -coverprofile="$OUTPUT_DIR/coverage.out" -covermode=atomic
|
||||
go tool cover -html="$OUTPUT_DIR/coverage.out" -o "$OUTPUT_DIR/coverage.html"
|
||||
else
|
||||
go test -v ./test/unit/... ./test/integration/... ./test/e2e/... ./test/property/... ./test/fuzzing/... ./test/security/...
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
echo "Invalid test level: $TEST_LEVEL. Use: basic, unit, integration, comprehensive, audit"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
|
||||
# Generate JUnit output if requested
|
||||
if [ "$JUNIT_OUTPUT" = "true" ]; then
|
||||
if command -v go-junit-report &> /dev/null; then
|
||||
go test -v "$PACKAGE_FILTER" 2>&1 | go-junit-report > "$OUTPUT_DIR/test-results.xml"
|
||||
else
|
||||
echo "go-junit-report not found. Install with: go install github.com/jstemmer/go-junit-report@latest"
|
||||
fi
|
||||
fi
|
||||
|
||||
echo "Test execution completed. Results in $OUTPUT_DIR"
|
||||
Reference in New Issue
Block a user