major-domo-v2/.gitlab-ci.yml
Cal Corum 62c658fb57 CLAUDE: Add automated weekly transaction freeze/thaw system
Implements comprehensive automated system for weekly transaction freeze periods
with priority-based contested player resolution.

New Features:
- Weekly freeze/thaw task (Monday 00:00 freeze, Saturday 00:00 thaw)
- Priority resolution for contested transactions (worst teams get first priority)
- Admin league management commands (/freeze-begin, /freeze-end, /advance-week)
- Enhanced API client to handle string-based transaction IDs (moveids)
- Service layer methods for transaction cancellation, unfreezing, and bulk operations
- Offseason mode configuration flag to disable freeze operations

Technical Changes:
- api/client.py: URL-encode object_id parameter to handle colons in moveids
- bot.py: Initialize and shutdown transaction freeze task
- config.py: Add offseason_flag to BotConfig
- services/league_service.py: Add update_current_state() for week/freeze updates
- services/transaction_service.py: Add cancel/unfreeze methods with bulk support
- tasks/transaction_freeze.py: Main freeze/thaw automation with error recovery
- commands/admin/league_management.py: Manual admin controls for freeze system

Infrastructure:
- .gitlab-ci.yml and .gitlab/: GitLab CI/CD pipeline configuration
- .mcp.json: MCP server configuration
- Dockerfile.versioned: Versioned Docker build support
- .dockerignore: Added .gitlab/ to ignore list

Testing:
- tests/test_tasks_transaction_freeze.py: Comprehensive freeze task tests

The system uses team standings to fairly resolve contested players (multiple teams
trying to acquire the same player), with worst-record teams getting priority.
Includes comprehensive error handling, GM notifications, and admin reporting.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-20 12:16:13 -05:00

238 lines
6.5 KiB
YAML

stages:
- test
- build
- deploy
variables:
DOCKER_IMAGE: yourusername/discord-bot-v2
DOCKER_DRIVER: overlay2
# Semantic versioning - update these for releases
VERSION_MAJOR: "2"
VERSION_MINOR: "1"
# Test on all branches
test:
stage: test
image: python:3.11-slim
before_script:
- cd discord-app-v2
- pip install --cache-dir .cache/pip -r requirements.txt
script:
- python -m pytest --tb=short -q --cov=. --cov-report=term-missing
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- .cache/pip
only:
- branches
artifacts:
reports:
coverage_report:
coverage_format: cobertura
path: discord-app-v2/coverage.xml
# Build with versioned tags
build:
stage: build
image: docker:24-dind
services:
- docker:24-dind
before_script:
- docker login -u $DOCKER_USERNAME -p $DOCKER_PASSWORD
script:
- cd discord-app-v2
# Calculate version tags
- export VERSION_PATCH=${CI_PIPELINE_IID}
- export FULL_VERSION="v${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_PATCH}"
- export SHORT_SHA=${CI_COMMIT_SHORT_SHA}
- export BRANCH_TAG="${CI_COMMIT_REF_SLUG}-${SHORT_SHA}"
# Build once, tag multiple times
- |
docker build \
--build-arg VERSION=${FULL_VERSION} \
--build-arg GIT_COMMIT=${CI_COMMIT_SHA} \
--build-arg BUILD_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") \
-t ${DOCKER_IMAGE}:${FULL_VERSION} \
-t ${DOCKER_IMAGE}:${SHORT_SHA} \
-t ${DOCKER_IMAGE}:${BRANCH_TAG} \
.
# Tag as latest only for main branch
- |
if [ "$CI_COMMIT_BRANCH" == "main" ]; then
docker tag ${DOCKER_IMAGE}:${FULL_VERSION} ${DOCKER_IMAGE}:latest
fi
# Tag as staging for develop branch
- |
if [ "$CI_COMMIT_BRANCH" == "develop" ]; then
docker tag ${DOCKER_IMAGE}:${FULL_VERSION} ${DOCKER_IMAGE}:staging
fi
# Push all tags
- docker push ${DOCKER_IMAGE}:${FULL_VERSION}
- docker push ${DOCKER_IMAGE}:${SHORT_SHA}
- docker push ${DOCKER_IMAGE}:${BRANCH_TAG}
- |
if [ "$CI_COMMIT_BRANCH" == "main" ]; then
docker push ${DOCKER_IMAGE}:latest
fi
- |
if [ "$CI_COMMIT_BRANCH" == "develop" ]; then
docker push ${DOCKER_IMAGE}:staging
fi
# Save version info for deployment
- echo "FULL_VERSION=${FULL_VERSION}" > version.env
- echo "SHORT_SHA=${SHORT_SHA}" >> version.env
- echo "BRANCH_TAG=${BRANCH_TAG}" >> version.env
artifacts:
reports:
dotenv: discord-app-v2/version.env
only:
- main
- develop
- tags
# Deploy to staging (automatic for develop branch)
deploy:staging:
stage: deploy
image: alpine:latest
needs:
- build
before_script:
- apk add --no-cache openssh-client
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H $VPS_HOST >> ~/.ssh/known_hosts
script:
- echo "Deploying version ${FULL_VERSION} to staging..."
- |
ssh $VPS_USER@$VPS_HOST << EOF
cd /path/to/discord-bot-staging
# Backup current version
docker inspect discord-bot-staging --format='{{.Image}}' > .last_version || true
# Update docker-compose with specific version
sed -i 's|image: ${DOCKER_IMAGE}:.*|image: ${DOCKER_IMAGE}:staging|' docker-compose.yml
# Pull and deploy
docker-compose pull
docker-compose up -d
# Wait for health check
sleep 10
if docker-compose ps | grep -q "Up (healthy)"; then
echo "✅ Deployment successful!"
docker image prune -f
else
echo "❌ Health check failed!"
exit 1
fi
EOF
environment:
name: staging
url: https://staging-bot.yourdomain.com
only:
- develop
# Deploy to production (manual approval required)
deploy:production:
stage: deploy
image: alpine:latest
needs:
- build
before_script:
- apk add --no-cache openssh-client
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H $VPS_HOST >> ~/.ssh/known_hosts
script:
- echo "Deploying version ${FULL_VERSION} to production..."
- |
ssh $VPS_USER@$VPS_HOST << EOF
cd /path/to/discord-bot
# Backup current version for rollback
docker inspect discord-bot --format='{{.Image}}' > .last_version || true
echo "${FULL_VERSION}" > .deployed_version
# Create deployment record
echo "$(date -Iseconds) | ${FULL_VERSION} | ${CI_COMMIT_SHORT_SHA} | ${CI_COMMIT_MESSAGE}" >> deployments.log
# Update docker-compose with specific version tag
sed -i 's|image: ${DOCKER_IMAGE}:.*|image: ${DOCKER_IMAGE}:${FULL_VERSION}|' docker-compose.yml
# Pull and deploy
docker-compose pull
docker-compose up -d
# Wait for health check
sleep 10
if docker-compose ps | grep -q "Up (healthy)"; then
echo "✅ Deployment successful!"
echo "Deployed: ${FULL_VERSION}"
docker image prune -f
else
echo "❌ Health check failed! Rolling back..."
LAST_VERSION=\$(cat .last_version)
sed -i "s|image: ${DOCKER_IMAGE}:.*|image: \${LAST_VERSION}|" docker-compose.yml
docker-compose up -d
exit 1
fi
EOF
environment:
name: production
url: https://bot.yourdomain.com
when: manual # Require manual approval
only:
- main
- tags
# Rollback job (manual trigger)
rollback:production:
stage: deploy
image: alpine:latest
before_script:
- apk add --no-cache openssh-client
- mkdir -p ~/.ssh
- echo "$SSH_PRIVATE_KEY" | tr -d '\r' > ~/.ssh/id_rsa
- chmod 600 ~/.ssh/id_rsa
- ssh-keyscan -H $VPS_HOST >> ~/.ssh/known_hosts
script:
- |
ssh $VPS_USER@$VPS_HOST << 'EOF'
cd /path/to/discord-bot
# Show recent deployments
echo "Recent deployments:"
tail -n 10 deployments.log
# Get last successful version
LAST_VERSION=$(cat .last_version)
echo ""
echo "Rolling back to: ${LAST_VERSION}"
# Rollback
sed -i "s|image: ${DOCKER_IMAGE}:.*|image: ${LAST_VERSION}|" docker-compose.yml
docker-compose up -d
# Record rollback
echo "$(date -Iseconds) | ROLLBACK | ${LAST_VERSION}" >> deployments.log
echo "✅ Rollback complete!"
EOF
environment:
name: production
action: rollback
when: manual
only:
- main