diff --git a/.gitea/workflows/docker-build.yml b/.gitea/workflows/docker-build.yml index 01335cd..f7cd5d6 100644 --- a/.gitea/workflows/docker-build.yml +++ b/.gitea/workflows/docker-build.yml @@ -1,13 +1,10 @@ # Gitea Actions: Docker Build, Push, and Notify # -# This workflow provides a complete CI/CD pipeline for Major Domo Discord Bot: -# - Validates semantic versioning on PRs +# CI/CD pipeline for Major Domo Discord Bot: # - Builds Docker images on every push/PR -# - Pushes to Docker Hub on main branch merges +# - Auto-generates CalVer version (YYYY.MM.BUILD) on main branch merges +# - Pushes to Docker Hub and creates git tag on main # - Sends Discord notifications on success/failure -# -# Created: 2026-02-05 -# For: Major Domo Discord Bot v2.0 name: Build Docker Image @@ -24,166 +21,45 @@ jobs: runs-on: ubuntu-latest steps: - # ============================================== - # 1. CHECKOUT CODE - # ============================================== - name: Checkout code uses: actions/checkout@v4 + with: + fetch-depth: 0 # Full history for tag counting - # ============================================== - # 2. SEMANTIC VERSION VALIDATION (PRs only) - # ============================================== - # Enforces proper semantic versioning: - # - Blocks PRs that don't bump VERSION file - # - Validates version changes follow semver rules - # - Prevents skipping versions or going backwards - # - # Valid bumps: - # - Patch: 1.2.3 → 1.2.4 (bug fixes) - # - Minor: 1.2.3 → 1.3.0 (new features) - # - Major: 1.2.3 → 2.0.0 (breaking changes) - # - # Invalid bumps: - # - 1.2.3 → 1.4.0 (skipped minor version) - # - 1.2.3 → 1.2.0 (went backwards) - # - 1.2.3 → 1.3.1 (didn't reset patch) - # - - name: Check VERSION was bumped (semantic versioning) - if: github.event_name == 'pull_request' - run: | - # Get VERSION from this PR branch - PR_VERSION=$(cat VERSION 2>/dev/null || echo "0.0.0") - - # Get VERSION from main branch - git fetch origin main:main - MAIN_VERSION=$(git show main:VERSION 2>/dev/null || echo "0.0.0") - - echo "📋 Semantic Version Check" - echo "Main branch version: $MAIN_VERSION" - echo "PR branch version: $PR_VERSION" - echo "" - - # Parse versions into components - IFS='.' read -r MAIN_MAJOR MAIN_MINOR MAIN_PATCH <<< "$MAIN_VERSION" - IFS='.' read -r PR_MAJOR PR_MINOR PR_PATCH <<< "$PR_VERSION" - - # Remove any non-numeric characters - MAIN_MAJOR=${MAIN_MAJOR//[!0-9]/} - MAIN_MINOR=${MAIN_MINOR//[!0-9]/} - MAIN_PATCH=${MAIN_PATCH//[!0-9]/} - PR_MAJOR=${PR_MAJOR//[!0-9]/} - PR_MINOR=${PR_MINOR//[!0-9]/} - PR_PATCH=${PR_PATCH//[!0-9]/} - - # Check if VERSION unchanged - if [ "$PR_VERSION" = "$MAIN_VERSION" ]; then - echo "❌ ERROR: VERSION file has not been updated!" - echo "" - echo "Please update the VERSION file in your PR." - echo "Current version: $MAIN_VERSION" - exit 1 - fi - - # Validate semantic version bump - VALID=false - BUMP_TYPE="" - - # Check for major version bump (X.0.0) - if [ "$PR_MAJOR" -eq $((MAIN_MAJOR + 1)) ] && [ "$PR_MINOR" -eq 0 ] && [ "$PR_PATCH" -eq 0 ]; then - VALID=true - BUMP_TYPE="major" - # Check for minor version bump (x.X.0) - elif [ "$PR_MAJOR" -eq "$MAIN_MAJOR" ] && [ "$PR_MINOR" -eq $((MAIN_MINOR + 1)) ] && [ "$PR_PATCH" -eq 0 ]; then - VALID=true - BUMP_TYPE="minor" - # Check for patch version bump (x.x.X) - elif [ "$PR_MAJOR" -eq "$MAIN_MAJOR" ] && [ "$PR_MINOR" -eq "$MAIN_MINOR" ] && [ "$PR_PATCH" -eq $((MAIN_PATCH + 1)) ]; then - VALID=true - BUMP_TYPE="patch" - fi - - if [ "$VALID" = true ]; then - echo "✅ Valid $BUMP_TYPE version bump: $MAIN_VERSION → $PR_VERSION" - else - echo "❌ ERROR: Invalid semantic version change!" - echo "" - echo "Current version: $MAIN_VERSION" - echo "PR version: $PR_VERSION" - echo "" - echo "Valid version bumps:" - echo " - Patch: $MAIN_MAJOR.$MAIN_MINOR.$((MAIN_PATCH + 1))" - echo " - Minor: $MAIN_MAJOR.$((MAIN_MINOR + 1)).0" - echo " - Major: $((MAIN_MAJOR + 1)).0.0" - echo "" - echo "Common issues:" - echo " ❌ Skipping versions (e.g., 2.5.0 → 2.7.0)" - echo " ❌ Going backwards (e.g., 2.5.0 → 2.4.0)" - echo " ❌ Not resetting lower components (e.g., 2.5.0 → 2.6.1)" - exit 1 - fi - - # ============================================== - # 3. DOCKER BUILDX SETUP - # ============================================== - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - # ============================================== - # 4. DOCKER HUB LOGIN (main branch only) - # ============================================== - # Requires secrets in Gitea: - # - DOCKERHUB_USERNAME: Your Docker Hub username - # - DOCKERHUB_TOKEN: Docker Hub access token (not password!) - # - # To create token: - # 1. Go to hub.docker.com - # 2. Account Settings → Security → New Access Token - # 3. Copy token to Gitea repo → Settings → Secrets → Actions - # - name: Login to Docker Hub uses: docker/login-action@v3 with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - # ============================================== - # 5. EXTRACT METADATA - # ============================================== - # Reads VERSION file and generates image tags: - # - version: From VERSION file (e.g., "2.29.4") - # - sha_short: First 7 chars of commit SHA - # - version_sha: Combined version+commit (e.g., "v2.29.4-a1b2c3d") - # - branch: Current branch name - # - timestamp: ISO 8601 format for Discord - # - - name: Extract metadata + # Generate CalVer: YYYY.MM.BUILD + # BUILD = count of tags matching current month + 1 + - name: Generate CalVer version id: meta run: | - VERSION=$(cat VERSION 2>/dev/null || echo "0.0.0") + YEAR=$(date -u +%Y) + MONTH=$(date -u +%-m) + PREFIX="${YEAR}.${MONTH}." + + # Count existing tags for this month + git fetch --tags + BUILD=$(git tag -l "${PREFIX}*" | wc -l) + BUILD=$((BUILD + 1)) + + VERSION="${PREFIX}${BUILD}" SHA_SHORT=$(echo ${{ github.sha }} | cut -c1-7) + echo "version=${VERSION}" >> $GITHUB_OUTPUT echo "sha_short=${SHA_SHORT}" >> $GITHUB_OUTPUT - echo "version_sha=v${VERSION}-${SHA_SHORT}" >> $GITHUB_OUTPUT + echo "version_sha=${VERSION}-${SHA_SHORT}" >> $GITHUB_OUTPUT echo "branch=${{ github.ref_name }}" >> $GITHUB_OUTPUT echo "timestamp=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> $GITHUB_OUTPUT - # ============================================== - # 6. BUILD AND PUSH DOCKER IMAGE - # ============================================== - # Creates 3 tags for each build: - # - latest: Always points to newest build - # - v{VERSION}: Semantic version from VERSION file - # - v{VERSION}-{COMMIT}: Version + commit hash for traceability - # - # Example tags: - # - manticorum67/major-domo-discordapp:latest - # - manticorum67/major-domo-discordapp:v2.29.4 - # - manticorum67/major-domo-discordapp:v2.29.4-a1b2c3d - # - # Push behavior: - # - PRs: Build only (test), don't push - # - Main: Build and push to Docker Hub - # + echo "CalVer version: ${VERSION}" + - name: Build Docker image uses: docker/build-push-action@v5 with: @@ -191,24 +67,30 @@ jobs: push: ${{ github.ref == 'refs/heads/main' }} tags: | manticorum67/major-domo-discordapp:latest - manticorum67/major-domo-discordapp:v${{ steps.meta.outputs.version }} + manticorum67/major-domo-discordapp:${{ steps.meta.outputs.version }} manticorum67/major-domo-discordapp:${{ steps.meta.outputs.version_sha }} cache-from: type=registry,ref=manticorum67/major-domo-discordapp:buildcache cache-to: type=registry,ref=manticorum67/major-domo-discordapp:buildcache,mode=max - # ============================================== - # 7. BUILD SUMMARY - # ============================================== - # Creates a formatted summary visible in Actions UI - # Shows: image tags, build details, push status - # + # Create git tag and update VERSION file on successful push + - name: Tag release + if: success() && github.ref == 'refs/heads/main' + run: | + git config user.name "Gitea Actions" + git config user.email "actions@git.manticorum.com" + echo "${{ steps.meta.outputs.version }}" > VERSION + git add VERSION + git commit -m "chore: bump version to ${{ steps.meta.outputs.version }} [skip ci]" || true + git tag "${{ steps.meta.outputs.version }}" + git push origin main --tags + - name: Build Summary run: | - echo "## 🐳 Docker Build Successful! ✅" >> $GITHUB_STEP_SUMMARY + echo "## Docker Build Successful" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Image Tags:**" >> $GITHUB_STEP_SUMMARY echo "- \`manticorum67/major-domo-discordapp:latest\`" >> $GITHUB_STEP_SUMMARY - echo "- \`manticorum67/major-domo-discordapp:v${{ steps.meta.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY + echo "- \`manticorum67/major-domo-discordapp:${{ steps.meta.outputs.version }}\`" >> $GITHUB_STEP_SUMMARY echo "- \`manticorum67/major-domo-discordapp:${{ steps.meta.outputs.version_sha }}\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "**Build Details:**" >> $GITHUB_STEP_SUMMARY @@ -217,39 +99,26 @@ jobs: echo "- Timestamp: \`${{ steps.meta.outputs.timestamp }}\`" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY if [ "${{ github.ref }}" == "refs/heads/main" ]; then - echo "🚀 **Pushed to Docker Hub!**" >> $GITHUB_STEP_SUMMARY + echo "Pushed to Docker Hub!" >> $GITHUB_STEP_SUMMARY echo "" >> $GITHUB_STEP_SUMMARY echo "Pull with: \`docker pull manticorum67/major-domo-discordapp:latest\`" >> $GITHUB_STEP_SUMMARY else echo "_PR build - image not pushed to Docker Hub_" >> $GITHUB_STEP_SUMMARY fi - # ============================================== - # 8. DISCORD NOTIFICATION - SUCCESS - # ============================================== - # Sends green embed to Discord on successful builds - # - # Only fires on main branch pushes (not PRs) - # - # Setup: - # 1. Create webhook in Discord channel: - # Right-click channel → Edit → Integrations → Webhooks → New - # 2. Copy webhook URL - # 3. Add to Gitea: Settings → Secrets → Actions → DISCORD_WEBHOOK - # - name: Discord Notification - Success if: success() && github.ref == 'refs/heads/main' run: | curl -H "Content-Type: application/json" \ -d '{ "embeds": [{ - "title": "✅ Major Domo Build Successful", - "description": "Discord bot Docker image built and pushed to Docker Hub!", + "title": "Major Domo Bot - Build Successful", + "description": "Docker image built and pushed to Docker Hub", "color": 3066993, "fields": [ { "name": "Version", - "value": "`v${{ steps.meta.outputs.version }}`", + "value": "`${{ steps.meta.outputs.version }}`", "inline": true }, { @@ -257,11 +126,6 @@ jobs: "value": "`${{ steps.meta.outputs.version_sha }}`", "inline": true }, - { - "name": "Branch", - "value": "`${{ steps.meta.outputs.branch }}`", - "inline": true - }, { "name": "Commit", "value": "`${{ steps.meta.outputs.sha_short }}`", @@ -272,11 +136,6 @@ jobs: "value": "${{ github.actor }}", "inline": true }, - { - "name": "Docker Hub", - "value": "[manticorum67/major-domo-discordapp](https://hub.docker.com/r/manticorum67/major-domo-discordapp)", - "inline": false - }, { "name": "View Run", "value": "[Click here](${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }})", @@ -288,13 +147,6 @@ jobs: }' \ ${{ secrets.DISCORD_WEBHOOK }} - # ============================================== - # 9. DISCORD NOTIFICATION - FAILURE - # ============================================== - # Sends red embed to Discord on build failures - # - # Only fires on main branch pushes (not PRs) - # - name: Discord Notification - Failure if: failure() && github.ref == 'refs/heads/main' run: | @@ -302,8 +154,8 @@ jobs: curl -H "Content-Type: application/json" \ -d '{ "embeds": [{ - "title": "❌ Major Domo Build Failed", - "description": "Discord bot Docker build encountered an error.", + "title": "Major Domo Bot - Build Failed", + "description": "Docker build encountered an error.", "color": 15158332, "fields": [ { @@ -330,45 +182,4 @@ jobs: "timestamp": "'"$TIMESTAMP"'" }] }' \ - ${{ secrets.DISCORD_WEBHOOK }} - -# ============================================== -# SETUP CHECKLIST -# ============================================== -# Before this workflow will work: -# -# ✅ Add secrets to Gitea repo (Settings → Secrets → Actions): -# - DOCKERHUB_USERNAME: Your Docker Hub username (manticorum67) -# - DOCKERHUB_TOKEN: Docker Hub access token -# - DISCORD_WEBHOOK: Discord webhook URL for notifications -# -# ✅ Ensure VERSION file exists in repo root (currently at 2.29.4) -# -# ✅ Update branch name if not using "main" -# -# ============================================== -# TROUBLESHOOTING -# ============================================== -# Common issues and solutions: -# -# 1. VERSION validation failing unexpectedly -# - Ensure VERSION file exists in repo root -# - Check file contains only version number (no 'v' prefix or extra text) -# - Verify version follows semver: MAJOR.MINOR.PATCH -# -# 2. Docker Hub push failing -# - Verify DOCKERHUB_USERNAME and DOCKERHUB_TOKEN secrets are set -# - Check Docker Hub token has push permissions -# - Ensure repository name matches your Docker Hub repo exactly -# -# 3. Discord notifications not appearing -# - Verify DISCORD_WEBHOOK secret is set in Gitea -# - Test webhook URL manually with curl -# - Check webhook still exists in Discord channel settings -# -# 4. Build cache not working -# - Uses registry-based caching (pushes cache layers to Docker Hub) -# - Requires Docker Hub login to read/write cache -# - To clear cache: delete the buildcache tag on Docker Hub -# -# ============================================== + ${{ secrets.DISCORD_WEBHOOK }} \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index fb82916..14cfded 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -51,20 +51,28 @@ class MyCog(commands.Cog): # Business logic only - decorator handles logging, timing, errors ``` -## Deployment +## Deployment & Troubleshooting -### Production Environment -- **Host**: `ssh akamai` (Akamai cloud server) -- **Bot container**: `major-domo-discord-app-1` -- **Logs**: `ssh akamai "docker logs --since 1h major-domo-discord-app-1"` +### Production +- **Host**: `ssh akamai` → `cd container-data/major-domo` +- **Container**: `major-domo-discord-app-1` +- **Image**: `manticorum67/major-domo-discordapp` (no dash between discord and app) +- **Health**: Process liveness only (no HTTP endpoint) +- **CI/CD**: Gitea Actions on PR to `main` — builds Docker image, auto-generates CalVer version (`YYYY.MM.BUILD`) on merge - **Other services on same host**: `sba_db_api`, `sba_postgres`, `sba_redis`, `sba-website-sba-web-1`, `pd_api` -### CI/CD -Builds and deploys are handled by Gitea Actions. Create a PR to `main` using `tea`: -```bash -tea pulls create --repo cal/major-domo-v2 --head --base main --title "title" --description "description" -``` -Gitea validates the version, builds the Docker image, and deploys on merge. +### Logs +- **Container logs**: `ssh akamai "docker logs --since 1h major-domo-discord-app-1"` +- **Log file (in container)**: `/app/logs/discord_bot_v2.json` (JSON structured, rotating, 10MB max) +- **Host mount**: `./logs/discord_bot_v2.json` + +### Key Env Vars +`BOT_TOKEN`, `API_TOKEN`, `DB_URL`, `GUILD_ID`, `LOG_LEVEL`, `ENVIRONMENT`, `REDIS_URL` (optional) + +### Common Issues +- Bot not responding → check `docker logs`, verify `BOT_TOKEN` and `GUILD_ID` +- API errors → verify `DB_URL` points to correct database API and `API_TOKEN` matches +- Redis errors are non-fatal (graceful fallback when `REDIS_URL` is empty) ## API Reference - OpenAPI spec: https://sba.manticorum.com/api/openapi.json (use WebFetch for current endpoints)