diff --git a/.forgejo/workflows/docker-api.yml b/.forgejo/workflows/docker-api.yml new file mode 100644 index 0000000..aa0edd1 --- /dev/null +++ b/.forgejo/workflows/docker-api.yml @@ -0,0 +1,103 @@ +name: Docker API + +on: + push: + branches: [main] + paths: + - 'src/food-market.api/**' + - 'src/food-market.application/**' + - 'src/food-market.domain/**' + - 'src/food-market.infrastructure/**' + - 'src/food-market.shared/**' + - 'deploy/Dockerfile.api' + - 'deploy/docker-compose.yml' + - '.forgejo/workflows/docker-api.yml' + - 'food-market.sln' + workflow_dispatch: + +env: + LOCAL_REGISTRY: 127.0.0.1:5001 + +jobs: + build: + name: Build + push API + runs-on: [self-hosted, linux] + steps: + - uses: actions/checkout@v4 + + - name: Build + push (buildx with registry cache) + env: + SHA: ${{ github.sha }} + run: | + docker buildx create --use --name fmbuilder --driver docker-container 2>/dev/null \ + || docker buildx use fmbuilder + docker buildx build \ + -f deploy/Dockerfile.api \ + -t $LOCAL_REGISTRY/food-market-api:$SHA \ + -t $LOCAL_REGISTRY/food-market-api:latest \ + --cache-from type=registry,ref=$LOCAL_REGISTRY/food-market-api:buildcache \ + --cache-to type=registry,ref=$LOCAL_REGISTRY/food-market-api:buildcache,mode=max \ + --push . + + deploy: + name: Deploy API on stage + needs: build + runs-on: [self-hosted, linux] + steps: + - uses: actions/checkout@v4 + + - name: Update compose + .env + env: + PGPASS: ${{ secrets.STAGE_POSTGRES_PASSWORD }} + run: | + # Стенд использует :latest для обоих сервисов, .env переписываем + # идемпотентно — без затирания тэга соседнего сервиса. + cat > /home/nns/food-market-stage/deploy/.env < /dev/null + + - name: Notify Telegram on failure + if: failure() + env: + BOT: ${{ secrets.TELEGRAM_BOT_TOKEN }} + CHAT: ${{ secrets.TELEGRAM_CHAT_ID }} + SHA: ${{ github.sha }} + run: | + curl -sS -X POST "https://api.telegram.org/bot$BOT/sendMessage" \ + --data-urlencode "chat_id=$CHAT" \ + --data-urlencode "text=❌ stage api deploy FAILED — ${SHA:0:7}" \ + > /dev/null diff --git a/.forgejo/workflows/docker-web.yml b/.forgejo/workflows/docker-web.yml new file mode 100644 index 0000000..be13c08 --- /dev/null +++ b/.forgejo/workflows/docker-web.yml @@ -0,0 +1,97 @@ +name: Docker Web + +on: + push: + branches: [main] + paths: + - 'src/food-market.web/**' + - 'deploy/Dockerfile.web' + - 'deploy/nginx.conf' + - 'deploy/docker-compose.yml' + - '.forgejo/workflows/docker-web.yml' + workflow_dispatch: + +env: + LOCAL_REGISTRY: 127.0.0.1:5001 + +jobs: + build: + name: Build + push Web + runs-on: [self-hosted, linux] + steps: + - uses: actions/checkout@v4 + + - name: Build + push (buildx with registry cache) + env: + SHA: ${{ github.sha }} + run: | + docker buildx create --use --name fmbuilder --driver docker-container 2>/dev/null \ + || docker buildx use fmbuilder + docker buildx build \ + -f deploy/Dockerfile.web \ + -t $LOCAL_REGISTRY/food-market-web:$SHA \ + -t $LOCAL_REGISTRY/food-market-web:latest \ + --cache-from type=registry,ref=$LOCAL_REGISTRY/food-market-web:buildcache \ + --cache-to type=registry,ref=$LOCAL_REGISTRY/food-market-web:buildcache,mode=max \ + --push . + + deploy: + name: Deploy Web on stage + needs: build + runs-on: [self-hosted, linux] + steps: + - uses: actions/checkout@v4 + + - name: Update compose + .env + env: + PGPASS: ${{ secrets.STAGE_POSTGRES_PASSWORD }} + run: | + cat > /home/nns/food-market-stage/deploy/.env < /dev/null + + - name: Notify Telegram on failure + if: failure() + env: + BOT: ${{ secrets.TELEGRAM_BOT_TOKEN }} + CHAT: ${{ secrets.TELEGRAM_CHAT_ID }} + SHA: ${{ github.sha }} + run: | + curl -sS -X POST "https://api.telegram.org/bot$BOT/sendMessage" \ + --data-urlencode "chat_id=$CHAT" \ + --data-urlencode "text=❌ stage web deploy FAILED — ${SHA:0:7}" \ + > /dev/null diff --git a/.forgejo/workflows/docker.yml b/.forgejo/workflows/docker.yml deleted file mode 100644 index e0e939d..0000000 --- a/.forgejo/workflows/docker.yml +++ /dev/null @@ -1,191 +0,0 @@ -name: Docker Images - -on: - push: - branches: [main] - paths-ignore: - - '**.md' - - 'docs/**' - - '.github/**' - workflow_dispatch: - -env: - LOCAL_REGISTRY: 127.0.0.1:5001 - -jobs: - # Решает что именно изменилось в этом push'е, чтобы ниже собирать только нужные - # образы. Outputs `api` / `web` = "true"|"false". При workflow_dispatch — оба true. - changes: - name: Detect changes - runs-on: [self-hosted, linux] - outputs: - api: ${{ steps.filter.outputs.api }} - web: ${{ steps.filter.outputs.web }} - steps: - - uses: actions/checkout@v4 - with: - fetch-depth: 2 - - - id: filter - run: | - if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then - echo "api=true" >> "$GITHUB_OUTPUT" - echo "web=true" >> "$GITHUB_OUTPUT" - exit 0 - fi - base=$(git rev-parse HEAD~1 2>/dev/null || git rev-parse HEAD) - changed=$(git diff --name-only "$base" HEAD) - echo "Changed files since $base:" - echo "$changed" - api=false; web=false - while IFS= read -r f; do - [ -z "$f" ] && continue - case "$f" in - src/food-market.api/*|\ - src/food-market.application/*|\ - src/food-market.domain/*|\ - src/food-market.infrastructure/*|\ - src/food-market.shared/*|\ - deploy/Dockerfile.api|\ - deploy/docker-compose.yml|\ - .forgejo/workflows/docker.yml|\ - food-market.sln) - api=true ;; - esac - case "$f" in - src/food-market.web/*|\ - deploy/Dockerfile.web|\ - deploy/nginx.conf|\ - deploy/docker-compose.yml|\ - .forgejo/workflows/docker.yml) - web=true ;; - esac - done <<< "$changed" - echo "api=$api" >> "$GITHUB_OUTPUT" - echo "web=$web" >> "$GITHUB_OUTPUT" - echo "Result: api=$api web=$web" - - api: - name: API image - needs: changes - if: needs.changes.outputs.api == 'true' - runs-on: [self-hosted, linux] - steps: - - uses: actions/checkout@v4 - - - name: Build + push API (buildx with registry cache) - env: - SHA: ${{ github.sha }} - run: | - docker buildx create --use --name fmbuilder --driver docker-container 2>/dev/null \ - || docker buildx use fmbuilder - docker buildx build \ - -f deploy/Dockerfile.api \ - -t $LOCAL_REGISTRY/food-market-api:$SHA \ - -t $LOCAL_REGISTRY/food-market-api:latest \ - --cache-from type=registry,ref=$LOCAL_REGISTRY/food-market-api:buildcache \ - --cache-to type=registry,ref=$LOCAL_REGISTRY/food-market-api:buildcache,mode=max \ - --push . - - web: - name: Web image - needs: changes - if: needs.changes.outputs.web == 'true' - runs-on: [self-hosted, linux] - steps: - - uses: actions/checkout@v4 - - - name: Build + push Web (buildx with registry cache) - env: - SHA: ${{ github.sha }} - run: | - docker buildx create --use --name fmbuilder --driver docker-container 2>/dev/null \ - || docker buildx use fmbuilder - docker buildx build \ - -f deploy/Dockerfile.web \ - -t $LOCAL_REGISTRY/food-market-web:$SHA \ - -t $LOCAL_REGISTRY/food-market-web:latest \ - --cache-from type=registry,ref=$LOCAL_REGISTRY/food-market-web:buildcache \ - --cache-to type=registry,ref=$LOCAL_REGISTRY/food-market-web:buildcache,mode=max \ - --push . - - deploy-stage: - name: Deploy stage - needs: [changes, api, web] - # always() позволяет deploy запуститься даже если api/web был пропущен. - # Запускаем когда хотя бы один из api/web реально пересобрался ИЛИ менялся compose. - if: | - always() - && (needs.api.result == 'success' || needs.api.result == 'skipped') - && (needs.web.result == 'success' || needs.web.result == 'skipped') - && (needs.changes.outputs.api == 'true' || needs.changes.outputs.web == 'true') - runs-on: [self-hosted, linux] - steps: - - uses: actions/checkout@v4 - - - name: Write .env + copy compose (runner = stage host) - env: - SHA: ${{ github.sha }} - PGPASS: ${{ secrets.STAGE_POSTGRES_PASSWORD }} - run: | - # Если в этом ране какой-то из образов не пересобирался, используем :latest — - # текущий compose и так указывает на 127.0.0.1:5001/food-market-{api,web}:$TAG. - api_tag="$SHA"; web_tag="$SHA" - [ "${{ needs.changes.outputs.api }}" = "true" ] || api_tag=latest - [ "${{ needs.changes.outputs.web }}" = "true" ] || web_tag=latest - cat > /home/nns/food-market-stage/deploy/.env < /dev/null - - - name: Notify Telegram on failure - if: failure() - env: - BOT: ${{ secrets.TELEGRAM_BOT_TOKEN }} - CHAT: ${{ secrets.TELEGRAM_CHAT_ID }} - SHA: ${{ github.sha }} - run: | - curl -sS -X POST "https://api.telegram.org/bot$BOT/sendMessage" \ - --data-urlencode "chat_id=$CHAT" \ - --data-urlencode "text=❌ stage deploy FAILED — ${SHA:0:7}" \ - > /dev/null