Repository navigation
v0.6.7 #39
Workflow file for this run
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| name: Deploy | |
| on: | |
| release: | |
| types: [published] | |
| workflow_dispatch: | |
| inputs: | |
| tag: | |
| description: "Git tag to deploy (e.g. v0.2.5)" | |
| required: true | |
| db-reset: | |
| description: "Whether to wipe the database (true/false)" | |
| required: true | |
| default: "false" | |
| type: choice | |
| options: | |
| - "true" | |
| - "false" | |
| db-reset-confirm: | |
| description: "If db-reset is true, type WIPE to confirm" | |
| required: false | |
| default: "" | |
| concurrency: | |
| group: deploy-production | |
| cancel-in-progress: false | |
| jobs: | |
| deploy: | |
| runs-on: ubuntu-latest | |
| environment: toolforge | |
| steps: | |
| - uses: actions/checkout@v6 | |
| - name: Setup SSH | |
| run: | | |
| if [ -z "$SSH_HOST" ] || [ -z "$SSH_KEY" ] || [ -z "$SSH_USER" ]; then | |
| echo "::error::Missing required secrets (HOST, KEY, USERNAME). Configure them in the 'toolforge' environment." | |
| exit 1 | |
| fi | |
| mkdir -p ~/.ssh | |
| ssh-keyscan "$SSH_HOST" >> ~/.ssh/known_hosts | |
| echo "$SSH_KEY" > ~/.ssh/id_ed25519 | |
| chmod 600 ~/.ssh/id_ed25519 | |
| env: | |
| SSH_HOST: ${{ secrets.HOST }} | |
| SSH_KEY: ${{ secrets.KEY }} | |
| SSH_USER: ${{ secrets.USERNAME }} | |
| - name: Deploy to Toolforge | |
| timeout-minutes: 20 | |
| env: | |
| TAG: ${{ github.event.release.tag_name || github.event.inputs.tag }} | |
| DB_RESET: ${{ github.event_name == 'workflow_dispatch' && github.event.inputs['db-reset'] || 'false' }} | |
| DB_RESET_CONFIRM: ${{ github.event.inputs['db-reset-confirm'] || '' }} | |
| run: | | |
| set -euo pipefail | |
| if [ -z "${TAG:-}" ]; then | |
| echo "::error::TAG is empty. Provide a valid tag (e.g. v0.2.5)." | |
| exit 1 | |
| fi | |
| if ! [[ "$TAG" =~ ^[A-Za-z0-9._-]+$ ]]; then | |
| echo "::error::Invalid tag '$TAG'. Allowed characters: A-Z, a-z, 0-9, '.', '_', '-'." | |
| exit 1 | |
| fi | |
| if [ "$DB_RESET" = "true" ] && [ "$DB_RESET_CONFIRM" != "WIPE" ]; then | |
| echo "::error::DB reset requested but confirmation missing. Type 'WIPE' in the confirmation field." | |
| exit 1 | |
| fi | |
| cat > /tmp/deploy.sh << 'SCRIPT' | |
| set -euo pipefail | |
| TAG="$1" | |
| DB_RESET="${2:-false}" | |
| ACTOR="${3:-unknown}" | |
| case "$DB_RESET" in | |
| true|false) ;; | |
| *) | |
| echo "Invalid DB_RESET '$DB_RESET' (expected true/false)" | |
| exit 1 | |
| ;; | |
| esac | |
| echo "==> Building image from ref $TAG" | |
| toolforge build start --ref "$TAG" https://github.com/DiFronzo/WikiVisage.git 2>&1 | tail -5 | |
| echo "==> Waiting for build to complete..." | |
| ELAPSED=0 | |
| while [ $ELAPSED -lt 600 ]; do | |
| sleep 15 | |
| ELAPSED=$((ELAPSED + 15)) | |
| STATUS=$(toolforge build show --json 2>/dev/null | jq -r '.build.status // empty') | |
| if [ -z "$STATUS" ]; then | |
| echo "Waiting... (${ELAPSED}s) no status yet" | |
| continue | |
| fi | |
| case "$STATUS" in | |
| ok) | |
| echo "Build succeeded after ${ELAPSED}s" | |
| break | |
| ;; | |
| error|timeout) | |
| echo "Build failed with status: $STATUS" | |
| toolforge build show | |
| toolforge build logs 2>&1 | tail -20 | |
| exit 1 | |
| ;; | |
| cancelled) | |
| echo "Build was cancelled" | |
| exit 1 | |
| ;; | |
| pending|running|unknown) | |
| echo "Waiting... (${ELAPSED}s) status: $STATUS" | |
| ;; | |
| *) | |
| echo "Waiting... (${ELAPSED}s) unexpected status: $STATUS" | |
| ;; | |
| esac | |
| done | |
| if [ $ELAPSED -ge 600 ]; then | |
| echo "Build timed out after 600s" | |
| toolforge build show | |
| exit 1 | |
| fi | |
| echo "==> Deleting ml-worker 1" | |
| toolforge jobs delete ml-worker || true | |
| echo "==> Deleting ml-worker 2" | |
| toolforge jobs delete ml-worker-2 || true | |
| RESET_FLAG="" | |
| [ "$DB_RESET" = "true" ] && RESET_FLAG=" --reset" | |
| echo "==> Running migration (db-reset=$DB_RESET)" | |
| toolforge jobs run migrate --command "python migrate.py${RESET_FLAG}" --image tool-wikivisage/tool-wikivisage:latest --wait | |
| echo "==> Running ml-worker 1" | |
| toolforge jobs run ml-worker --command 'python -u worker.py --worker-id ml-worker-1' --image tool-wikivisage/tool-wikivisage:latest --continuous --mem 3Gi --cpu 2 | |
| echo "==> Running ml-worker 2" | |
| toolforge jobs run ml-worker-2 --command 'python -u worker.py --worker-id ml-worker-2' --image tool-wikivisage/tool-wikivisage:latest --continuous --mem 3Gi --cpu 2 | |
| echo "==> Restarting webservice" | |
| toolforge webservice buildservice restart | |
| LOG_MSG="deployed $TAG (by $ACTOR)" | |
| [ "$DB_RESET" = "true" ] && LOG_MSG="deployed $TAG with database wipe (by $ACTOR on GitHub)" | |
| dologmsg "$LOG_MSG" | |
| echo "==> Deploy complete (logged to SAL)" | |
| SCRIPT | |
| scp -i ~/.ssh/id_ed25519 /tmp/deploy.sh "${{ secrets.USERNAME }}@${{ secrets.HOST }}":/tmp/deploy.sh | |
| ssh -i ~/.ssh/id_ed25519 "${{ secrets.USERNAME }}@${{ secrets.HOST }}" \ | |
| "become wikivisage bash /tmp/deploy.sh '${TAG}' '${DB_RESET}' '${{ github.actor }}'" | |
| echo "## 🚀 Deploy Summary" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| | |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "|---|---|" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| **Tag** | \`${TAG}\` |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| **DB Reset** | \`${DB_RESET}\` |" >> "$GITHUB_STEP_SUMMARY" | |
| echo "| **Triggered by** | \`${{ github.actor }}\` |" >> "$GITHUB_STEP_SUMMARY" | |
| - name: Cleanup SSH | |
| if: always() | |
| run: rm -f ~/.ssh/id_ed25519 |