name: deploy-portainer # Ручной запуск: вкладка Actions → Run workflow. # Создаёт или обновляет стек photo-editor на Portainer # (https://ptr.byte-mate.ru) из deploy/docker-compose.yml. on: workflow_dispatch: concurrency: group: deploy cancel-in-progress: true jobs: deploy: runs-on: ubuntu-latest steps: - name: Checkout uses: actions/checkout@v4 - name: Deploy stack to Portainer env: PORTAINER_URL: https://ptr.byte-mate.ru PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }} # Секреты Gitea: Settings → Actions → Secrets → APP_USER / APP_PASSWORD APP_USER: ${{ secrets.APP_USER }} APP_PASSWORD: ${{ secrets.APP_PASSWORD }} STACK_NAME: photo-editor # Если не задано — берётся первый endpoint из /api/endpoints ENDPOINT_ID: ${{ vars.PORTAINER_ENDPOINT_ID }} run: | set -euo pipefail if [ -z "${PORTAINER_API_KEY:-}" ]; then echo "::error::Секрет PORTAINER_API_KEY не задан" echo "::error::Создайте API-ключ в Portainer (Account → API keys) и добавьте его в секреты репозитория." exit 1 fi AUTH="X-API-Key: ${PORTAINER_API_KEY}" # Параметры стека: пустые значения означают «дефолты на сервере» ENV_JSON=$(jq -nc \ --arg u "${APP_USER:-}" \ --arg p "${APP_PASSWORD:-}" \ '[{name:"APP_USER",value:$u},{name:"APP_PASSWORD",value:$p}]') # Определяем endpoint (окружение Docker), если не задан вручную if [ -z "${ENDPOINT_ID:-}" ]; then ENDPOINT_ID=$(curl -fsSk -H "$AUTH" "$PORTAINER_URL/api/endpoints" | jq -r '.[0].Id') echo "Endpoint id автоопределён: ${ENDPOINT_ID}" fi echo "Endpoint id: ${ENDPOINT_ID}" # Ищем существующий стек STACK_ID=$(curl -fsSk -H "$AUTH" \ "$PORTAINER_URL/api/stacks?filters=%7B%22EndpointId%22%3A${ENDPOINT_ID}%7D" \ | jq -r ".[] | select(.Name==\"${STACK_NAME}\") | .Id" | head -1 || true) if [ -n "${STACK_ID}" ]; then echo "Обновляю стек ${STACK_NAME} (id=${STACK_ID})" PAYLOAD=$(jq -nc \ --rawfile content deploy/docker-compose.yml \ --argjson env "$ENV_JSON" \ '{StackFileContent:$content, Env:$env, RepullImageAndRedeploy:true}') curl -fsSk -X PUT -H "$AUTH" -H 'Content-Type: application/json' \ -d "$PAYLOAD" \ "$PORTAINER_URL/api/stacks/${STACK_ID}?endpointId=${ENDPOINT_ID}" >/dev/null else echo "Создаю стек ${STACK_NAME}" curl -fsSk -X POST -H "$AUTH" \ -F "Name=${STACK_NAME}" \ -F "file=@deploy/docker-compose.yml" \ -F "Env=${ENV_JSON}" \ "$PORTAINER_URL/api/stacks/create/standalone/file?endpointId=${ENDPOINT_ID}" >/dev/null fi echo "✅ Стек ${STACK_NAME} развёрнут на ${PORTAINER_URL}"