name: Deploy to Portainer via API on: workflow_run: workflows: ["Build and Push Docker Image"] # Matches the 'name:' of the build workflow types: - completed jobs: deploy: runs-on: ubuntu-latest name: Deploy Application to Portainer # IMPORTANT: The 'if' condition and 'github.event' paths use GitHub Actions syntax. # For Gitea, you'll likely need to replace 'github.event' with 'gitea.event' # and verify the exact payload structure in your Gitea documentation. if: ${{ github.event.workflow_run.conclusion == 'success' }} # Only run if the build workflow succeeded env: PORTAINER_URL: ${{ secrets.PORTAINER_URL }} PORTAINER_API_KEY: ${{ secrets.PORTAINER_API_KEY }} PORTAINER_ENVIRONMENT_ID: ${{ secrets.PORTAINER_ENVIRONMENT_ID }} # Define your target image name - constructed similarly to the build workflow # Ensure REGISTRY_URL is available (e.g., from Gitea vars or hardcoded if truly static for this deployment) # Gitea equivalent for repo full name likely: ${{ gitea.event.workflow_run.repository.full_name }} IMAGE_TO_DEPLOY: ${{ vars.REGISTRY_URL }}/${{ gitea.repository }}:latest CONTAINER_NAME: ${{ vars.PORTAINER_CONTAINER_NAME || 'deep-research' }} # Name of the container in Portainer HOST_PORT: "8005" # Host port to map to container's 3000 CONTAINER_PORT: "3000" # Container port RESTART_POLICY: "unless-stopped" # For curl: -k allows insecure connections (e.g. self-signed certs). Omit for production with valid certs. # CURL_OPTS: "-s -k" # If you need -k CURL_OPTS: "-s" # Silent mode steps: - name: Deploy Container to Portainer run: | set -e # Exit immediately if a command exits with a non-zero status. echo "Starting deployment of image ${{ env.IMAGE_TO_DEPLOY }} as container ${{ env.CONTAINER_NAME }}" PORTAINER_API_DOCKER_BASE="${{ env.PORTAINER_URL }}/api/endpoints/${{ env.PORTAINER_ENVIRONMENT_ID }}/docker" AUTH_HEADER="X-API-Key: ${{ env.PORTAINER_API_KEY }}" # 1. Find existing container by name echo "Searching for existing container named '${{ env.CONTAINER_NAME }}'..." # Portainer API often prepends '/' to container names in the .Names field. # Using jq to filter based on any name in the .Names array matching / EXISTING_CONTAINER_ID=$(curl ${{ env.CURL_OPTS }} -H "$AUTH_HEADER" \ "${PORTAINER_API_DOCKER_BASE}/containers/json?all=true" | \ jq -r --arg CN "/${{ env.CONTAINER_NAME }}" '.[] | select(.Names[] | contains($CN)) | .Id' | head -n 1) # 2. If container exists, stop and remove it if [ -n "$EXISTING_CONTAINER_ID" ]; then echo "Found existing container '${{ env.CONTAINER_NAME }}' with ID '$EXISTING_CONTAINER_ID'." echo "Stopping container..." curl ${{ env.CURL_OPTS }} -X POST -H "$AUTH_HEADER" "${PORTAINER_API_DOCKER_BASE}/containers/${EXISTING_CONTAINER_ID}/stop" echo "Waiting for container to stop..." sleep 5 # Adjust sleep time as needed echo "Removing container..." curl ${{ env.CURL_OPTS }} -X DELETE -H "$AUTH_HEADER" "${PORTAINER_API_DOCKER_BASE}/containers/${EXISTING_CONTAINER_ID}" echo "Container '${{ env.CONTAINER_NAME }}' removed." else echo "No existing container named '${{ env.CONTAINER_NAME }}' found." fi # 3. Create new container echo "Creating new container '${{ env.CONTAINER_NAME }}' with image '${{ env.IMAGE_TO_DEPLOY }}'..." CREATE_PAYLOAD=$(cat <