From 935e95eab94d11ed471e4aaeb85451aaaea63d32 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Mon, 27 Oct 2025 17:24:47 +0100 Subject: [PATCH 01/28] add deployment script for single env and namespace --- scripts/deploy_to_hf.sh | 466 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 466 insertions(+) create mode 100755 scripts/deploy_to_hf.sh diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh new file mode 100755 index 00000000..08a8b0b9 --- /dev/null +++ b/scripts/deploy_to_hf.sh @@ -0,0 +1,466 @@ +#!/bin/bash + +# OpenEnv Hugging Face Deployment Preparation Script +# This script prepares files for deployment to Hugging Face Spaces + +set -euo pipefail + +usage() { + cat <<'EOF' +Usage: scripts/prepare_hf_deployment.sh --env [options] + +Required arguments: + --env Environment name under src/envs (e.g. textarena_env) + +Optional arguments: + --base-sha Override openenv-base image reference (defaults to :latest) + --hf-namespace Hugging Face username/organization (defaults to HF_USERNAME/HF_USER or meta-openenv) + --staging-dir Output directory for staging (defaults to hf-staging) + -h, --help Show this help message + +Positional compatibility: + You can also call the script as: + scripts/prepare_hf_deployment.sh [base_image_sha] + +Examples: + scripts/prepare_hf_deployment.sh --env textarena_env --hf-namespace my-team + scripts/prepare_hf_deployment.sh chat_env sha-0123456789abcdef +EOF +} + +sed_in_place() { + local expression="$1" + local target_file="$2" + if sed --version >/dev/null 2>&1; then + sed -i "$expression" "$target_file" + else + sed -i '' "$expression" "$target_file" + fi +} + +SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) +REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd) +cd "$REPO_ROOT" + +ENV_NAME="" +BASE_IMAGE_SHA="" +HF_NAMESPACE="${HF_NAMESPACE:-}" +STAGING_DIR="hf-staging" + +while [[ $# -gt 0 ]]; do + case "$1" in + --env) + ENV_NAME="$2" + shift 2 + ;; + --base-sha|--base-image-sha) + BASE_IMAGE_SHA="$2" + shift 2 + ;; + --hf-namespace|--hf-user|--hf-username) + HF_NAMESPACE="$2" + shift 2 + ;; + --staging-dir) + STAGING_DIR="$2" + shift 2 + ;; + -h|--help) + usage + exit 0 + ;; + --) + shift + break + ;; + -* ) + echo "Unknown option: $1" >&2 + usage + exit 1 + ;; + *) + if [ -z "$ENV_NAME" ]; then + ENV_NAME="$1" + elif [ -z "$BASE_IMAGE_SHA" ]; then + BASE_IMAGE_SHA="$1" + else + echo "Unexpected positional argument: $1" >&2 + usage + exit 1 + fi + shift + ;; + esac +done + +if [ -z "$ENV_NAME" ]; then + echo "Error: Environment name is required" >&2 + usage + exit 1 +fi + +if [[ "$ENV_NAME" == *","* || "$ENV_NAME" == *" "* ]]; then + echo "Error: only one environment can be deployed per invocation (received '$ENV_NAME')." >&2 + exit 1 +fi + +if [ ! -d "src/envs/$ENV_NAME" ]; then + echo "Error: Environment '$ENV_NAME' not found under src/envs" >&2 + exit 1 +fi + +if [ -z "$HF_NAMESPACE" ]; then + if [ -n "${HF_USERNAME:-}" ]; then + HF_NAMESPACE="$HF_USERNAME" + elif [ -n "${HF_USER:-}" ]; then + HF_NAMESPACE="$HF_USER" + else + HF_NAMESPACE="meta-openenv" + fi +fi + +# Set base image reference (using GHCR) +if [ -n "$BASE_IMAGE_SHA" ]; then + BASE_IMAGE_REF="ghcr.io/meta-pytorch/openenv-base:$BASE_IMAGE_SHA" + echo "Using specific SHA for openenv-base: $BASE_IMAGE_SHA" +else + BASE_IMAGE_REF="ghcr.io/meta-pytorch/openenv-base:latest" + echo "Using latest tag for openenv-base" +fi + +echo "Preparing $ENV_NAME environment for deployment..." + +# Create staging directory +CURRENT_STAGING_DIR="${STAGING_DIR}/${HF_NAMESPACE}/${ENV_NAME}" +mkdir -p "$CURRENT_STAGING_DIR/src/core" +mkdir -p "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME" + +# Copy core files +cp -R src/core/ "$CURRENT_STAGING_DIR/src/core/" +echo "Copied core files" + +# Copy environment files +cp -R "src/envs/$ENV_NAME/" "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME/" +echo "Copied $ENV_NAME environment files" + +# Create environment-specific multi-stage Dockerfile +create_environment_dockerfile() { + local env_name=$1 + + # Create base Dockerfile + cat > "$CURRENT_STAGING_DIR/Dockerfile" << DOCKERFILE_EOF +# Copyright (c) Meta Platforms, Inc. and affiliates. +# All rights reserved. +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +# Use the specified openenv-base image +FROM $BASE_IMAGE_REF +DOCKERFILE_EOF + + # Add environment-specific dependencies + case $env_name in + "echo_env") + # Echo environment needs no additional dependencies + ;; + "coding_env") + cat >> "$CURRENT_STAGING_DIR/Dockerfile" << 'DOCKERFILE_EOF' +# Install smolagents for code execution +RUN pip install --no-cache-dir smolagents +DOCKERFILE_EOF + ;; + "chat_env") + cat >> "$CURRENT_STAGING_DIR/Dockerfile" << 'DOCKERFILE_EOF' +# Install additional dependencies for ChatEnvironment +RUN pip install --no-cache-dir torch transformers + +# Set up cache directory for Hugging Face models +RUN mkdir -p /.cache && chmod 777 /.cache +ENV HF_HOME=/.cache +ENV TRANSFORMERS_CACHE=/.cache + +# Pre-download the GPT-2 model to avoid permission issues during runtime +RUN python -c "from transformers import GPT2Tokenizer; GPT2Tokenizer.from_pretrained('gpt2')" +DOCKERFILE_EOF + ;; + "atari_env") + cat >> "$CURRENT_STAGING_DIR/Dockerfile" << 'DOCKERFILE_EOF' +# Install ALE-specific dependencies +RUN pip install --no-cache-dir \ + gymnasium>=0.29.0 \ + ale-py>=0.8.0 \ + numpy>=1.24.0 +DOCKERFILE_EOF + ;; + "textarena_env") + cat >> "$CURRENT_STAGING_DIR/Dockerfile" << 'DOCKERFILE_EOF' +# Install system libraries required by TextArena +RUN apt-get update && apt-get install -y --no-install-recommends \ + libgl1 \ + libglib2.0-0 \ + && rm -rf /var/lib/apt/lists/* + +# Install TextArena and supporting Python packages +RUN pip install --no-cache-dir \ + textarena==0.6.1 \ + nltk==3.9.2 +DOCKERFILE_EOF + ;; + "openspiel_env") + # OpenSpiel requires special C++ build process - replace entire Dockerfile + cat > "$CURRENT_STAGING_DIR/Dockerfile" << DOCKERFILE_EOF +# OpenSpiel environment using pre-built OpenSpiel base image +ARG OPENSPIEL_BASE_IMAGE=ghcr.io/meta-pytorch/openenv-openspiel-base:sha-e622c7e +FROM \${OPENSPIEL_BASE_IMAGE} + +# Copy OpenEnv core (base image already set WORKDIR=/app) +WORKDIR /app +COPY src/core/ /app/src/core/ + +# Copy OpenSpiel environment +COPY src/envs/openspiel_env/ /app/src/envs/openspiel_env/ + +# Copy README for web interface documentation +COPY src/envs/openspiel_env/README.md /app/README.md + +# Extend Python path for OpenEnv (base image set PYTHONPATH=/app/src) +# We prepend OpenSpiel paths +ENV PYTHONPATH=/repo:/repo/build/python:/app/src + +# OpenSpiel-specific environment variables (can be overridden at runtime) +ENV OPENSPIEL_GAME=catch +ENV OPENSPIEL_AGENT_PLAYER=0 +ENV OPENSPIEL_OPPONENT_POLICY=random + +# Health check (curl is provided by openenv-base) +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:8000/health || exit 1 + +# Note: EXPOSE 8000 already set by openenv-base + +# Run the FastAPI server (uvicorn installed by openenv-base) +CMD ["uvicorn", "envs.openspiel_env.server.app:app", "--host", "0.0.0.0", "--port", "8000"] +DOCKERFILE_EOF + echo "Created special OpenSpiel Dockerfile with C++ build process" + echo "OpenSpiel builds can take 10-15 minutes due to C++ compilation" + return # Skip the common parts since OpenSpiel has its own complete Dockerfile + ;; + esac + + # Add common parts + cat >> "$CURRENT_STAGING_DIR/Dockerfile" << 'DOCKERFILE_EOF' + +# Copy only what's needed for this environment +COPY src/core/ /app/src/core/ +COPY src/envs/ENV_NAME_PLACEHOLDER/ /app/src/envs/ENV_NAME_PLACEHOLDER/ + +# Health check +HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \ + CMD curl -f http://localhost:8000/health || exit 1 + +# Run the FastAPI server +CMD ["uvicorn", "envs.ENV_NAME_PLACEHOLDER.server.app:app", "--host", "0.0.0.0", "--port", "8000"] +DOCKERFILE_EOF + + # Replace placeholder with actual environment name + sed_in_place "s/ENV_NAME_PLACEHOLDER/$env_name/g" "$CURRENT_STAGING_DIR/Dockerfile" +} + +create_environment_dockerfile "$ENV_NAME" + +# Add web interface support +echo "ENV ENABLE_WEB_INTERFACE=true" >> $CURRENT_STAGING_DIR/Dockerfile +echo "Added web interface support" + +# Create environment-specific README +create_readme() { + local env_name=$1 + + # Capitalize first letter of environment name + env_title=$(echo "$env_name" | awk '{print toupper(substr($0,1,1)) substr($0,2)}') + + # Set environment-specific colors and emoji + case $env_name in + "atari_env") + EMOJI="đŸ•šī¸" + COLOR_FROM="red" + COLOR_TO="yellow" + ;; + "coding_env") + EMOJI="đŸ’ģ" + COLOR_FROM="blue" + COLOR_TO="gray" + ;; + "openspiel_env") + EMOJI="🎮" + COLOR_FROM="purple" + COLOR_TO="indigo" + ;; + "echo_env") + EMOJI="🔊" + COLOR_FROM="blue" + COLOR_TO="gray" + ;; + "chat_env") + EMOJI="đŸ’Ŧ" + COLOR_FROM="blue" + COLOR_TO="green" + ;; + "textarena_env") + EMOJI="📜" + COLOR_FROM="green" + COLOR_TO="blue" + ;; + *) + EMOJI="đŸŗ" + COLOR_FROM="blue" + COLOR_TO="green" + ;; + esac + + cat > "$CURRENT_STAGING_DIR/README.md" << README_EOF +--- +title: ${env_title} Environment Server +emoji: ${EMOJI} +colorFrom: ${COLOR_FROM} +colorTo: ${COLOR_TO} +sdk: docker +pinned: false +app_port: 8000 +base_path: /web +--- + +# ${env_title} Environment Server + +FastAPI server for ${env_name} environment powered by Meta's OpenEnv. + +## About + +This Space provides a containerized environment for ${env_name} interactions. +Built with FastAPI and OpenEnv framework. + +## Web Interface + +This deployment includes an interactive web interface for exploring the environment: +- **HumanAgent Interface**: Interact with the environment using a web form +- **State Observer**: Real-time view of environment state and action history +- **Live Updates**: WebSocket-based real-time updates + +Access the web interface at: \`/web\` + +README_EOF + + # Add environment-specific information + case $env_name in + "echo_env") + cat >> "$CURRENT_STAGING_DIR/README.md" << 'README_EOF' +## Echo Environment + +Simple test environment that echoes back messages. Perfect for testing the OpenEnv APIs. + +### Usage +Send a POST request to `/step` with: +```json +{ + "message": "Hello World" +} +``` +README_EOF + ;; + "coding_env") + cat >> "$CURRENT_STAGING_DIR/README.md" << 'README_EOF' +## Coding Environment + +Executes Python code in a sandboxed environment with safety checks. + +### Usage +Send a POST request to `/step` with: +```json +{ + "code": "print('Hello World')" +} +``` +README_EOF + ;; + "chat_env") + cat >> "$CURRENT_STAGING_DIR/README.md" << 'README_EOF' +## Chat Environment + +Provides a chat-based interface for LLMs with tokenization support. + +### Usage +Send a POST request to `/step` with tokenized input: +```json +{ + "tokens": [1, 2, 3, 4, 5] +} +``` +README_EOF + ;; + "atari_env") + cat >> "$CURRENT_STAGING_DIR/README.md" << 'README_EOF' +## Atari Environment + +Provides Atari 2600 games via the Arcade Learning Environment (ALE). + +### Usage +Send a POST request to `/step` with: +```json +{ + "action_id": 0, + "game_name": "pong" +} +``` +README_EOF + ;; + "openspiel_env") + cat >> "$CURRENT_STAGING_DIR/README.md" << 'README_EOF' +## OpenSpiel Environment + +Provides access to OpenSpiel games for multi-agent reinforcement learning. + +### Usage +Send a POST request to `/step` with: +```json +{ + "action": { + "action_id": 1 + } +} +``` +README_EOF + ;; + "textarena_env") + cat >> "$CURRENT_STAGING_DIR/README.md" << 'README_EOF' +## TextArena Environment + +Runs TextArena games such as Wordle, GuessTheNumber, or Chess through a unified HTTP API. + +### Usage +Send a POST request to `/step` with: +```json +{ + "message": "raise shield" +} +``` +README_EOF + ;; + *) + cat >> "$CURRENT_STAGING_DIR/README.md" << 'README_EOF' + +## API Documentation + +Visit `/docs` for interactive API documentation. + +## Health Check + +The environment provides a health check endpoint at `/health`. +README_EOF + ;; + esac +} + +create_readme "$ENV_NAME" +echo "Created README for HF Space" +echo "Completed preparation for $ENV_NAME environment" From 0c74d5c38b0573e6f556af10f0e1751a3c1d75dc Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Mon, 27 Oct 2025 19:50:48 +0100 Subject: [PATCH 02/28] add push step and simplify logging --- scripts/deploy_to_hf.sh | 94 +++++++++++++++++++++++++++++++++++------ 1 file changed, 80 insertions(+), 14 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 08a8b0b9..892bb446 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -7,7 +7,7 @@ set -euo pipefail usage() { cat <<'EOF' -Usage: scripts/prepare_hf_deployment.sh --env [options] +Usage: scripts/deploy_to_hf.sh --env [options] Required arguments: --env Environment name under src/envs (e.g. textarena_env) @@ -16,15 +16,16 @@ Optional arguments: --base-sha Override openenv-base image reference (defaults to :latest) --hf-namespace Hugging Face username/organization (defaults to HF_USERNAME/HF_USER or meta-openenv) --staging-dir Output directory for staging (defaults to hf-staging) + --dry-run Prepare files without pushing to Hugging Face Spaces -h, --help Show this help message Positional compatibility: You can also call the script as: - scripts/prepare_hf_deployment.sh [base_image_sha] + scripts/deploy_to_hf.sh [base_image_sha] Examples: - scripts/prepare_hf_deployment.sh --env textarena_env --hf-namespace my-team - scripts/prepare_hf_deployment.sh chat_env sha-0123456789abcdef + scripts/deploy_to_hf.sh --env textarena_env --hf-namespace my-team + scripts/deploy_to_hf.sh chat_env sha-0123456789abcdef EOF } @@ -42,10 +43,29 @@ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd) cd "$REPO_ROOT" +if ! command -v hf >/dev/null 2>&1; then + echo "Error: huggingface-hub CLI 'hf' not found in PATH. hf is required to deploy to Hugging Face Spaces." >&2 + + if [ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]; then + echo "Install the HF CLI: curl -LsSf https://hf.co/cli/install.sh | sh" >&2 + elif [ "$OSTYPE" == "windows"* ]; then + echo "Install the HF CLI: powershell -ExecutionPolicy ByPass -c \"irm https://hf.co/cli/install.ps1 | iex\"" >&2 + fi + + exit 1 +fi + +HF_USERNAME=$(hf auth whoami | head -n1 | tr -d '\n') + +if [ -z "${HF_NAMESPACE:-}" ]; then + echo "🙋 Using default namespace: $HF_USERNAME. You can override the namespace with --hf-namespace" + HF_NAMESPACE="${HF_USERNAME:-}" +fi + ENV_NAME="" BASE_IMAGE_SHA="" -HF_NAMESPACE="${HF_NAMESPACE:-}" STAGING_DIR="hf-staging" +DRY_RUN=false while [[ $# -gt 0 ]]; do case "$1" in @@ -65,6 +85,10 @@ while [[ $# -gt 0 ]]; do STAGING_DIR="$2" shift 2 ;; + --dry-run) + DRY_RUN=true + shift + ;; -h|--help) usage exit 0 @@ -125,11 +149,8 @@ if [ -n "$BASE_IMAGE_SHA" ]; then echo "Using specific SHA for openenv-base: $BASE_IMAGE_SHA" else BASE_IMAGE_REF="ghcr.io/meta-pytorch/openenv-base:latest" - echo "Using latest tag for openenv-base" fi -echo "Preparing $ENV_NAME environment for deployment..." - # Create staging directory CURRENT_STAGING_DIR="${STAGING_DIR}/${HF_NAMESPACE}/${ENV_NAME}" mkdir -p "$CURRENT_STAGING_DIR/src/core" @@ -137,11 +158,9 @@ mkdir -p "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME" # Copy core files cp -R src/core/ "$CURRENT_STAGING_DIR/src/core/" -echo "Copied core files" - # Copy environment files cp -R "src/envs/$ENV_NAME/" "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME/" -echo "Copied $ENV_NAME environment files" +echo "📁 Copied core and $ENV_NAME environment files to $CURRENT_STAGING_DIR" # Create environment-specific multi-stage Dockerfile create_environment_dockerfile() { @@ -271,7 +290,6 @@ create_environment_dockerfile "$ENV_NAME" # Add web interface support echo "ENV ENABLE_WEB_INTERFACE=true" >> $CURRENT_STAGING_DIR/Dockerfile -echo "Added web interface support" # Create environment-specific README create_readme() { @@ -462,5 +480,53 @@ README_EOF } create_readme "$ENV_NAME" -echo "Created README for HF Space" -echo "Completed preparation for $ENV_NAME environment" +echo "📝 Created README and web interface support for HF Space" + +if $DRY_RUN; then + echo "👀 Dry run enabled; skipping Hugging Face upload." + exit 0 +fi + +echo "🔑 Ensuring Hugging Face authentication..." + +# just get the env token if it's set +if [ -n "${HF_TOKEN:-}" ]; then + hf auth login --token "$HF_TOKEN" --add-to-git-credential >/dev/null 2>&1 || true +fi + +# ask the user to login if they're not authenticated +if ! hf auth whoami >/dev/null 2>&1; then + hf auth login +fi + +if ! hf auth whoami >/dev/null 2>&1; then + echo "Error: Hugging Face authentication failed" >&2 + exit 1 +fi + +# ensure hf authentication on the namespace +# Check if the user has access to the target HF_NAMESPACE/org +if ! hf auth whoami | grep -qw "$HF_NAMESPACE"; then + echo "Error: Your account does not have access to the Hugging Face namespace '$HF_NAMESPACE'." >&2 + echo "Get the correct access token from https://huggingface.co/settings/tokens and set if with 'hf auth login' " >&2 + exit 1 +fi + +SPACE_REPO="${HF_NAMESPACE}/${ENV_NAME}-test" +CURRENT_STAGING_DIR_ABS=$(cd "$CURRENT_STAGING_DIR" && pwd) + +# create the space if it doesn't exist +hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok --quiet >/dev/null 2>&1 || true +# upload the staged content +SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space --quiet "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS") +if [ $? -ne 0 ]; then + echo "❌ Upload failed: $SPACE_UPLOAD_RESULT" >&2 + exit 1 +fi +# print the URL of the deployed space +echo "✅ Upload completed for https://huggingface.co/spaces/$SPACE_REPO" + +# safely cleanup the staging directory +if [ -d "$CURRENT_STAGING_DIR_ABS" ]; then + rm -rf "$CURRENT_STAGING_DIR_ABS" +fi From f5a676a88b86615de9208c627faa6318373a7bf3 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Mon, 27 Oct 2025 19:53:22 +0100 Subject: [PATCH 03/28] remove windows elif --- scripts/deploy_to_hf.sh | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 892bb446..18ed7bb8 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -45,13 +45,7 @@ cd "$REPO_ROOT" if ! command -v hf >/dev/null 2>&1; then echo "Error: huggingface-hub CLI 'hf' not found in PATH. hf is required to deploy to Hugging Face Spaces." >&2 - - if [ "$OSTYPE" == "linux-gnu"* || "$OSTYPE" == "darwin"* ]; then - echo "Install the HF CLI: curl -LsSf https://hf.co/cli/install.sh | sh" >&2 - elif [ "$OSTYPE" == "windows"* ]; then - echo "Install the HF CLI: powershell -ExecutionPolicy ByPass -c \"irm https://hf.co/cli/install.ps1 | iex\"" >&2 - fi - + echo "Install the HF CLI: curl -LsSf https://hf.co/cli/install.sh | sh" >&2 exit 1 fi From 10518ed39702c398fbe63dc5b0c4f72502dc648f Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 08:29:55 +0100 Subject: [PATCH 04/28] make deploy script compatible with gh actions --- scripts/deploy_to_hf.sh | 77 ++++++++++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 25 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 18ed7bb8..5464a137 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -14,8 +14,9 @@ Required arguments: Optional arguments: --base-sha Override openenv-base image reference (defaults to :latest) - --hf-namespace Hugging Face username/organization (defaults to HF_USERNAME/HF_USER or meta-openenv) + --hf-namespace Hugging Face username/organization (defaults to HF_USERNAME or meta-openenv) --staging-dir Output directory for staging (defaults to hf-staging) + --space-suffix Suffix to add to space name (e.g., "-test" for test spaces) --dry-run Prepare files without pushing to Hugging Face Spaces -h, --help Show this help message @@ -43,22 +44,27 @@ SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) REPO_ROOT=$(cd "$SCRIPT_DIR/.." && pwd) cd "$REPO_ROOT" -if ! command -v hf >/dev/null 2>&1; then - echo "Error: huggingface-hub CLI 'hf' not found in PATH. hf is required to deploy to Hugging Face Spaces." >&2 - echo "Install the HF CLI: curl -LsSf https://hf.co/cli/install.sh | sh" >&2 - exit 1 +# Detect if we're running in GitHub Actions +IS_GITHUB_ACTIONS=false +if [ -n "${GITHUB_ACTIONS:-}" ]; then + IS_GITHUB_ACTIONS=true fi -HF_USERNAME=$(hf auth whoami | head -n1 | tr -d '\n') - -if [ -z "${HF_NAMESPACE:-}" ]; then - echo "🙋 Using default namespace: $HF_USERNAME. You can override the namespace with --hf-namespace" - HF_NAMESPACE="${HF_USERNAME:-}" +# Check for hf CLI - but allow dry-run mode to work without it +if ! command -v hf >/dev/null 2>&1; then + echo "Warning: huggingface-hub CLI 'hf' not found in PATH." >&2 + echo "Install the HF CLI: curl -LsSf https://hf.co/cli/install.sh | sh" >&2 + if [ "${1:-}" != "--dry-run" ] && [ "${2:-}" != "--dry-run" ]; then + echo "Error: hf is required for deployment (use --dry-run to skip deployment)" >&2 + exit 1 + fi fi ENV_NAME="" BASE_IMAGE_SHA="" +HF_NAMESPACE="${HF_NAMESPACE:-}" # Initialize from env var if set, otherwise empty STAGING_DIR="hf-staging" +SPACE_SUFFIX="" DRY_RUN=false while [[ $# -gt 0 ]]; do @@ -71,7 +77,7 @@ while [[ $# -gt 0 ]]; do BASE_IMAGE_SHA="$2" shift 2 ;; - --hf-namespace|--hf-user|--hf-username) + --namespace|--hf-namespace|--hf-user|--hf-username) HF_NAMESPACE="$2" shift 2 ;; @@ -79,6 +85,10 @@ while [[ $# -gt 0 ]]; do STAGING_DIR="$2" shift 2 ;; + --suffix|--space-suffix) + SPACE_SUFFIX="$2" + shift 2 + ;; --dry-run) DRY_RUN=true shift @@ -127,16 +137,22 @@ if [ ! -d "src/envs/$ENV_NAME" ]; then exit 1 fi +# Try to get HF_USERNAME, but handle failures gracefully (especially in CI before auth) +if command -v hf >/dev/null 2>&1; then + HF_USERNAME=$(hf auth whoami 2>/dev/null | head -n1 | tr -d '\n' || echo "") +fi + if [ -z "$HF_NAMESPACE" ]; then + # Check HF_USERNAME (env var or detected from CLI) if [ -n "${HF_USERNAME:-}" ]; then - HF_NAMESPACE="$HF_USERNAME" - elif [ -n "${HF_USER:-}" ]; then - HF_NAMESPACE="$HF_USER" + HF_NAMESPACE="${HF_USERNAME}" else HF_NAMESPACE="meta-openenv" fi fi +echo "🙋 Using namespace: $HF_NAMESPACE. You can override with --hf-namespace" + # Set base image reference (using GHCR) if [ -n "$BASE_IMAGE_SHA" ]; then BASE_IMAGE_REF="ghcr.io/meta-pytorch/openenv-base:$BASE_IMAGE_SHA" @@ -483,30 +499,41 @@ fi echo "🔑 Ensuring Hugging Face authentication..." -# just get the env token if it's set -if [ -n "${HF_TOKEN:-}" ]; then +# In GitHub Actions, always use HF_TOKEN if provided +if [ "$IS_GITHUB_ACTIONS" = true ] && [ -n "${HF_TOKEN:-}" ]; then + echo "Using HF_TOKEN from GitHub Actions environment" + hf auth login --token "$HF_TOKEN" --add-to-git-credential >/dev/null 2>&1 || { + echo "Warning: Failed to authenticate with HF_TOKEN, continuing anyway..." >&2 + } +elif [ -n "${HF_TOKEN:-}" ]; then + # In local environment, try to use HF_TOKEN if set hf auth login --token "$HF_TOKEN" --add-to-git-credential >/dev/null 2>&1 || true fi -# ask the user to login if they're not authenticated -if ! hf auth whoami >/dev/null 2>&1; then +# In interactive mode (not CI), ask user to login if needed +if [ "$IS_GITHUB_ACTIONS" != true ] && ! hf auth whoami >/dev/null 2>&1; then + echo "Not authenticated. Please login to Hugging Face..." hf auth login fi +# Verify authentication if ! hf auth whoami >/dev/null 2>&1; then echo "Error: Hugging Face authentication failed" >&2 + if [ "$IS_GITHUB_ACTIONS" = true ]; then + echo "Ensure HF_TOKEN secret is set in GitHub Actions" >&2 + else + echo "Run 'hf auth login' or set HF_TOKEN environment variable" >&2 + fi exit 1 fi -# ensure hf authentication on the namespace -# Check if the user has access to the target HF_NAMESPACE/org -if ! hf auth whoami | grep -qw "$HF_NAMESPACE"; then - echo "Error: Your account does not have access to the Hugging Face namespace '$HF_NAMESPACE'." >&2 +CURRENT_USER=$(hf auth whoami | head -n1 | tr -d '\n') +if [ "$CURRENT_USER" != "$HF_NAMESPACE" ] && ! hf auth whoami | grep -qw "$HF_NAMESPACE" 2>/dev/null; then + echo "Warning: Your account ($CURRENT_USER) may not have direct access to namespace '$HF_NAMESPACE'." >&2 echo "Get the correct access token from https://huggingface.co/settings/tokens and set if with 'hf auth login' " >&2 - exit 1 fi -SPACE_REPO="${HF_NAMESPACE}/${ENV_NAME}-test" +SPACE_REPO="${HF_NAMESPACE}/${ENV_NAME}${SPACE_SUFFIX}" CURRENT_STAGING_DIR_ABS=$(cd "$CURRENT_STAGING_DIR" && pwd) # create the space if it doesn't exist @@ -520,7 +547,7 @@ fi # print the URL of the deployed space echo "✅ Upload completed for https://huggingface.co/spaces/$SPACE_REPO" -# safely cleanup the staging directory +# Cleanup the staging directory after successful deployment if [ -d "$CURRENT_STAGING_DIR_ABS" ]; then rm -rf "$CURRENT_STAGING_DIR_ABS" fi From ffb7acf202c6f57952eaa2d6c886a524515f190f Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 08:30:27 +0100 Subject: [PATCH 05/28] make gh action compatible with deploy script --- .github/workflows/deploy-hf-env.yml | 134 +++------------------------- 1 file changed, 12 insertions(+), 122 deletions(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index fdf505c5..dfc555ca 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -101,73 +101,18 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up Git + - name: Install Hugging Face CLI run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - - - name: Prepare files for HF Space - run: | - chmod +x scripts/prepare_hf_deployment.sh - ./scripts/prepare_hf_deployment.sh "${{ matrix.environment }}" "${{ github.event.inputs.base_image_sha || '' }}" + curl -LsSf https://hf.co/cli/install.sh | bash + echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Deploy to Hugging Face Space env: HF_TOKEN: ${{ secrets.HF_TOKEN }} - HF_USERNAME: openenv + HF_NAMESPACE: ${{ env.HF_USERNAME }} run: | - ENV_NAME="${{ matrix.environment }}" - SPACE_NAME="$ENV_NAME" - - echo "Deploying $ENV_NAME environment to HF Space: $SPACE_NAME" - - # Clone the target space - HF_SPACE_URL="https://$HF_USERNAME:$HF_TOKEN@huggingface.co/spaces/$HF_USERNAME/$SPACE_NAME" - echo "Cloning HF Space..." - - if git clone $HF_SPACE_URL hf-space 2>/dev/null; then - echo "Space exists, updating..." - else - echo "Space doesn't exist, will be created on first push" - mkdir -p hf-space - cd hf-space - git init - git remote add origin $HF_SPACE_URL - cd .. - fi - - cd hf-space - - # Clear existing files (except .git) - find . -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + - - # Copy prepared files - cp -r ../hf-staging_$ENV_NAME/* . - - # Set the correct remote URL - git remote set-url origin $HF_SPACE_URL - - # Check if there are changes - if [ -n "$(git status --porcelain)" ]; then - echo "Committing changes..." - git add . - git commit -m "🤖 Deploy $ENV_NAME environment - $(date +'%Y-%m-%d %H:%M:%S')" - - echo "Pushing to Hugging Face..." - if git push origin main 2>/dev/null || git push origin master 2>/dev/null; then - echo "✅ Successfully deployed to https://huggingface.co/spaces/$HF_USERNAME/$SPACE_NAME" - else - echo "❌ Failed to push to Hugging Face. Check your credentials and permissions." - exit 1 - fi - else - echo "â„šī¸ No changes to deploy" - fi - - # Cleanup - cd .. - rm -rf hf-space - rm -rf hf-staging_$ENV_NAME + chmod +x scripts/deploy_to_hf.sh + ./scripts/deploy_to_hf.sh "${{ matrix.environment }}" "${{ github.event.inputs.base_image_sha || '' }}" # Job to deploy single environment deploy-single: @@ -184,70 +129,15 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Set up Git + - name: Install Hugging Face CLI run: | - git config --global user.email "github-actions[bot]@users.noreply.github.com" - git config --global user.name "github-actions[bot]" - - - name: Prepare files for HF Space - run: | - chmod +x scripts/prepare_hf_deployment.sh - ./scripts/prepare_hf_deployment.sh "${{ matrix.environment }}" "${{ github.event.inputs.base_image_sha || '' }}" + curl -LsSf https://hf.co/cli/install.sh | bash + echo "$HOME/.local/bin" >> $GITHUB_PATH - name: Deploy to Hugging Face Space env: HF_TOKEN: ${{ secrets.HF_TOKEN }} - HF_USERNAME: openenv + HF_NAMESPACE: ${{ env.HF_USERNAME }} run: | - ENV_NAME="${{ matrix.environment }}" - SPACE_NAME="$ENV_NAME" - - echo "Deploying $ENV_NAME environment to HF Space: $SPACE_NAME" - - # Clone the target space - HF_SPACE_URL="https://$HF_USERNAME:$HF_TOKEN@huggingface.co/spaces/$HF_USERNAME/$SPACE_NAME" - echo "Cloning HF Space..." - - if git clone $HF_SPACE_URL hf-space 2>/dev/null; then - echo "Space exists, updating..." - else - echo "Space doesn't exist, will be created on first push" - mkdir -p hf-space - cd hf-space - git init - git remote add origin $HF_SPACE_URL - cd .. - fi - - cd hf-space - - # Clear existing files (except .git) - find . -mindepth 1 -maxdepth 1 ! -name '.git' -exec rm -rf {} + - - # Copy prepared files - cp -r ../hf-staging_$ENV_NAME/* . - - # Set the correct remote URL - git remote set-url origin $HF_SPACE_URL - - # Check if there are changes - if [ -n "$(git status --porcelain)" ]; then - echo "Committing changes..." - git add . - git commit -m "🤖 Deploy $ENV_NAME environment - $(date +'%Y-%m-%d %H:%M:%S')" - - echo "Pushing to Hugging Face..." - if git push origin main 2>/dev/null || git push origin master 2>/dev/null; then - echo "✅ Successfully deployed to https://huggingface.co/spaces/$HF_USERNAME/$SPACE_NAME" - else - echo "❌ Failed to push to Hugging Face. Check your credentials and permissions." - exit 1 - fi - else - echo "â„šī¸ No changes to deploy" - fi - - # Cleanup - cd .. - rm -rf hf-space - rm -rf hf-staging_$ENV_NAME + chmod +x scripts/deploy_to_hf.sh + ./scripts/deploy_to_hf.sh "${{ matrix.environment }}" "${{ github.event.inputs.base_image_sha || '' }}" From 2f6c64140474fe3ec2a3c0f75365466bbe3633e0 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 08:34:58 +0100 Subject: [PATCH 06/28] expose private flag in bash script --- scripts/deploy_to_hf.sh | 19 ++++++++++++++++--- 1 file changed, 16 insertions(+), 3 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 5464a137..62b14f1e 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -17,6 +17,7 @@ Optional arguments: --hf-namespace Hugging Face username/organization (defaults to HF_USERNAME or meta-openenv) --staging-dir Output directory for staging (defaults to hf-staging) --space-suffix Suffix to add to space name (e.g., "-test" for test spaces) + --private Deploy the space as private (default: public) --dry-run Prepare files without pushing to Hugging Face Spaces -h, --help Show this help message @@ -27,6 +28,7 @@ Positional compatibility: Examples: scripts/deploy_to_hf.sh --env textarena_env --hf-namespace my-team scripts/deploy_to_hf.sh chat_env sha-0123456789abcdef + scripts/deploy_to_hf.sh echo_env --private --hf-namespace my-org EOF } @@ -65,6 +67,7 @@ BASE_IMAGE_SHA="" HF_NAMESPACE="${HF_NAMESPACE:-}" # Initialize from env var if set, otherwise empty STAGING_DIR="hf-staging" SPACE_SUFFIX="" +PRIVATE=false DRY_RUN=false while [[ $# -gt 0 ]]; do @@ -89,6 +92,10 @@ while [[ $# -gt 0 ]]; do SPACE_SUFFIX="$2" shift 2 ;; + --private) + PRIVATE=true + shift + ;; --dry-run) DRY_RUN=true shift @@ -536,10 +543,16 @@ fi SPACE_REPO="${HF_NAMESPACE}/${ENV_NAME}${SPACE_SUFFIX}" CURRENT_STAGING_DIR_ABS=$(cd "$CURRENT_STAGING_DIR" && pwd) +# Determine privacy flag (only add --private if needed, default is public) +PRIVATE_FLAG="" +if [ "$PRIVATE" = true ]; then + PRIVATE_FLAG="--private" +fi + # create the space if it doesn't exist -hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok --quiet >/dev/null 2>&1 || true -# upload the staged content -SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space --quiet "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS") +hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG --quiet >/dev/null 2>&1 || true +# upload the staged content (if repo doesn't exist, it will be created with the privacy setting) +SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space $PRIVATE_FLAG --quiet "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS") if [ $? -ne 0 ]; then echo "❌ Upload failed: $SPACE_UPLOAD_RESULT" >&2 exit 1 From 3ffe2ce3485e5aaa627a80f18375476217ab702b Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 08:37:47 +0100 Subject: [PATCH 07/28] use params in gh action --- .github/workflows/deploy-hf-env.yml | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index dfc555ca..e330dc84 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -112,7 +112,11 @@ jobs: HF_NAMESPACE: ${{ env.HF_USERNAME }} run: | chmod +x scripts/deploy_to_hf.sh - ./scripts/deploy_to_hf.sh "${{ matrix.environment }}" "${{ github.event.inputs.base_image_sha || '' }}" + if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --base-sha "${{ github.event.inputs.base_image_sha }}" + else + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" + fi # Job to deploy single environment deploy-single: @@ -140,4 +144,8 @@ jobs: HF_NAMESPACE: ${{ env.HF_USERNAME }} run: | chmod +x scripts/deploy_to_hf.sh - ./scripts/deploy_to_hf.sh "${{ matrix.environment }}" "${{ github.event.inputs.base_image_sha || '' }}" + if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --base-sha "${{ github.event.inputs.base_image_sha }}" + else + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" + fi From b2e79043da2b219055838bcae1a107d195560bbc Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 08:38:45 +0100 Subject: [PATCH 08/28] add suffixes and privacy to gh action for testing purposes --- .github/workflows/deploy-hf-env.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index e330dc84..dc1c5e47 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -145,7 +145,7 @@ jobs: run: | chmod +x scripts/deploy_to_hf.sh if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then - ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --base-sha "${{ github.event.inputs.base_image_sha }}" + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --base-sha "${{ github.event.inputs.base_image_sha }}" --private --suffix -test else - ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --private --suffix -test fi From 80bb0d861acf94a2a796a69b22ec6b7de7802036 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 08:43:07 +0100 Subject: [PATCH 09/28] edit docs --- scripts/deploy_to_hf.sh | 1 - 1 file changed, 1 deletion(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 62b14f1e..cb4d312c 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -27,7 +27,6 @@ Positional compatibility: Examples: scripts/deploy_to_hf.sh --env textarena_env --hf-namespace my-team - scripts/deploy_to_hf.sh chat_env sha-0123456789abcdef scripts/deploy_to_hf.sh echo_env --private --hf-namespace my-org EOF } From 8a53bb117b21de96548c8a4c9ce19307ee6c6d71 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 08:57:39 +0100 Subject: [PATCH 10/28] fix hf_token in workflow --- TESTING.md | 201 ++++++++++++++++++++++++++++++++++++++++ scripts/deploy_to_hf.sh | 12 ++- 2 files changed, 208 insertions(+), 5 deletions(-) create mode 100644 TESTING.md diff --git a/TESTING.md b/TESTING.md new file mode 100644 index 00000000..73c94b45 --- /dev/null +++ b/TESTING.md @@ -0,0 +1,201 @@ +# Testing Guide for deploy_to_hf.sh + +## Local Script Testing + +### 1. Dry-Run Test (Safest - No Deployment) + +Test the script without actually deploying: + +```bash +# Test with dry-run (prepares files but doesn't upload) +./scripts/deploy_to_hf.sh echo_env --dry-run + +# Verify the staging directory was created +ls -la hf-staging/ + +# Check the generated files +tree hf-staging/ -L 3 +``` + +**What to verify:** +- ✅ Staging directory created at `hf-staging//` +- ✅ `Dockerfile` exists and looks correct +- ✅ `README.md` exists with correct metadata +- ✅ `src/core/` and `src/envs//` are copied correctly +- ✅ No deployment attempted (no HF API calls) + +### 2. Test with Test Namespace + +Deploy to your personal test space: + +```bash +# Use your HF username and add -test suffix to avoid affecting production +./scripts/deploy_to_hf.sh echo_env \ + --hf-namespace $(hf auth whoami | head -n1) \ + --space-suffix -test + +# Or use positional arguments +./scripts/deploy_to_hf.sh echo_env "" "$(hf auth whoami | head -n1)" +``` + +**What to verify:** +- ✅ Space created at `https://huggingface.co/spaces//echo_env-test` +- ✅ Files uploaded correctly +- ✅ Space builds successfully (check Space logs) + +### 3. Test Different Environments + +```bash +# Test smallest environment first (echo_env) +./scripts/deploy_to_hf.sh echo_env --dry-run + +# Test with specific base image SHA +./scripts/deploy_to_hf.sh echo_env --base-sha abc123 --dry-run + +# Test other environments +./scripts/deploy_to_hf.sh coding_env --dry-run +./scripts/deploy_to_hf.sh chat_env --dry-run +``` + +### 4. Validate Generated Files + +After dry-run, inspect the generated files: + +```bash +# Check Dockerfile +cat hf-staging//echo_env/Dockerfile + +# Check README +cat hf-staging//echo_env/README.md + +# Verify structure +find hf-staging//echo_env -type f +``` + +## GitHub Actions Testing + +### 0. Do I Need to Merge to Main? + +**No!** You can test from any branch: + +**Option A: Test from feature branch** +1. Push your changes (including workflow file) to your branch +2. Go to GitHub → Actions tab +3. Use the branch dropdown to select your branch +4. Find "Deploy to Hugging Face Environment" workflow +5. Click "Run workflow" → Select your branch → Run + +**Option B: Merge to main first** (easier to find) +- Workflows are most visible from the default branch +- After merge, they're easier to access in the Actions tab + +**Recommendation:** Test locally first, then test from your branch before merging. + +### 1. Manual Workflow Dispatch + +1. Go to GitHub → Actions → "Deploy to Hugging Face Environment" +2. Click "Run workflow" +3. Select: + - Environment: `echo_env` (start with smallest) + - Base image SHA: Leave empty (or test with specific SHA) +4. Click "Run workflow" + +**What to verify:** +- ✅ Workflow runs without errors +- ✅ HF CLI installs correctly +- ✅ Script executes successfully +- ✅ Space deployed to `openenv/echo_env` + +### 2. Test All Environments (Matrix) + +1. Run workflow with environment: `all` +2. This will deploy all environments in parallel +3. Monitor all matrix jobs + +### 3. Test Automatic Trigger + +Make a change to trigger automatic deployment: + +```bash +# Make a small change to core +echo "# Test" >> src/core/client_types.py +git add src/core/client_types.py +git commit -m "test: trigger deployment" +git push +``` + +**What to verify:** +- ✅ Workflow triggers automatically +- ✅ All environments deploy (because core changed) +- ✅ Only changed environments deploy (if only one env changed) + +### 4. Check Workflow Logs + +After workflow runs: +1. Click on the workflow run +2. Check each job's logs +3. Verify: + - ✅ HF CLI installation succeeded + - ✅ Script executed without errors + - ✅ Deployment succeeded + - ✅ Space URL printed at end + +## Verification Checklist + +### After Local Dry-Run +- [ ] Staging directory structure correct +- [ ] Dockerfile uses correct base image +- [ ] README.md has correct metadata +- [ ] All source files copied +- [ ] No sensitive files included + +### After Local Deployment +- [ ] Space appears on Hugging Face +- [ ] Space builds successfully (check build logs) +- [ ] Space is accessible via web UI +- [ ] API endpoints respond correctly + +### After GitHub Actions Deployment +- [ ] All matrix jobs succeeded +- [ ] Spaces deployed to correct namespace (`openenv/`) +- [ ] Spaces build successfully +- [ ] No authentication errors +- [ ] Script output shows success message + +## Common Issues & Debugging + +### Issue: "hf CLI not found" +```bash +# Install HF CLI locally +curl -LsSf https://hf.co/cli/install.sh | sh +# Reload shell or add to PATH +export PATH="$HOME/.local/bin:$PATH" +``` + +### Issue: "Authentication failed" +```bash +# Authenticate +hf auth login +# Or set token +export HF_TOKEN=your_token_here +``` + +### Issue: "Namespace access denied" +- Verify your HF token has access to the target namespace +- For org namespaces, token needs org permissions +- Check: `hf auth whoami` + +### Issue: "Script fails in GitHub Actions" +1. Check if `HF_TOKEN` secret is set in repository settings +2. Verify token has correct permissions (write access to spaces) +3. Check workflow logs for detailed error messages + +## Testing Checklist + +Before merging: +- [ ] Local dry-run works for all environments +- [ ] Local deployment works to test namespace +- [ ] GitHub Actions workflow runs successfully +- [ ] At least one environment deployed via CI +- [ ] Deployed space builds and runs correctly + diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index cb4d312c..d37433ec 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -505,12 +505,14 @@ fi echo "🔑 Ensuring Hugging Face authentication..." -# In GitHub Actions, always use HF_TOKEN if provided -if [ "$IS_GITHUB_ACTIONS" = true ] && [ -n "${HF_TOKEN:-}" ]; then +# In GitHub Actions, HF CLI automatically uses HF_TOKEN env var +if [ "$IS_GITHUB_ACTIONS" = true ]; then + if [ -z "${HF_TOKEN:-}" ]; then + echo "Error: HF_TOKEN secret is required in GitHub Actions" >&2 + echo "Please set the HF_TOKEN secret in repository settings" >&2 + exit 1 + fi echo "Using HF_TOKEN from GitHub Actions environment" - hf auth login --token "$HF_TOKEN" --add-to-git-credential >/dev/null 2>&1 || { - echo "Warning: Failed to authenticate with HF_TOKEN, continuing anyway..." >&2 - } elif [ -n "${HF_TOKEN:-}" ]; then # In local environment, try to use HF_TOKEN if set hf auth login --token "$HF_TOKEN" --add-to-git-credential >/dev/null 2>&1 || true From 6fd0e9167204ca69621f790f99c4351a23c70ce7 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 09:11:43 +0100 Subject: [PATCH 11/28] expose convenience parameters from gh action --- .github/workflows/deploy-hf-env.yml | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index dc1c5e47..d37952d1 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -20,6 +20,21 @@ on: required: false type: string default: '' + hf_namespace: + description: 'Hugging Face namespace to deploy to (leave empty for openenv)' + required: false + type: string + default: 'openenv' + private: + description: 'Deploy the space as private (default: public)' + required: false + type: boolean + default: false + space_suffix: + description: 'Suffix to add to space name (e.g., "-test" for test spaces)' + required: false + type: string + default: '' env: HF_USERNAME: openenv From d412459e8425d36ee30c26ff58aef204c95dd5fb Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 09:14:06 +0100 Subject: [PATCH 12/28] add a explicit tokn login --- scripts/deploy_to_hf.sh | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index d37433ec..5f1a93e4 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -505,14 +505,21 @@ fi echo "🔑 Ensuring Hugging Face authentication..." -# In GitHub Actions, HF CLI automatically uses HF_TOKEN env var +# In GitHub Actions, explicitly authenticate with token if [ "$IS_GITHUB_ACTIONS" = true ]; then if [ -z "${HF_TOKEN:-}" ]; then echo "Error: HF_TOKEN secret is required in GitHub Actions" >&2 echo "Please set the HF_TOKEN secret in repository settings" >&2 exit 1 fi - echo "Using HF_TOKEN from GitHub Actions environment" + echo "Authenticating with HF_TOKEN..." + LOGIN_OUTPUT=$(hf auth login --token "$HF_TOKEN" 2>&1) + LOGIN_EXIT_CODE=$? + if [ $LOGIN_EXIT_CODE -ne 0 ]; then + echo "Error: Failed to authenticate with HF_TOKEN" >&2 + echo "$LOGIN_OUTPUT" >&2 + exit 1 + fi elif [ -n "${HF_TOKEN:-}" ]; then # In local environment, try to use HF_TOKEN if set hf auth login --token "$HF_TOKEN" --add-to-git-credential >/dev/null 2>&1 || true From 6e90d0adcb696f259c9fc96777ccbde48c9efd0e Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 09:14:23 +0100 Subject: [PATCH 13/28] remove testing params --- .github/workflows/deploy-hf-env.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index d37952d1..eabd2382 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -160,7 +160,7 @@ jobs: run: | chmod +x scripts/deploy_to_hf.sh if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then - ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --base-sha "${{ github.event.inputs.base_image_sha }}" --private --suffix -test + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --base-sha "${{ github.event.inputs.base_image_sha }}" else - ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" --private --suffix -test + ./scripts/deploy_to_hf.sh --env "${{ matrix.environment }}" fi From 3cfe697819fad071b8c898b8a4030a0512cb1f41 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 09:21:45 +0100 Subject: [PATCH 14/28] remove testing notes --- TESTING.md | 201 ----------------------------------------------------- 1 file changed, 201 deletions(-) delete mode 100644 TESTING.md diff --git a/TESTING.md b/TESTING.md deleted file mode 100644 index 73c94b45..00000000 --- a/TESTING.md +++ /dev/null @@ -1,201 +0,0 @@ -# Testing Guide for deploy_to_hf.sh - -## Local Script Testing - -### 1. Dry-Run Test (Safest - No Deployment) - -Test the script without actually deploying: - -```bash -# Test with dry-run (prepares files but doesn't upload) -./scripts/deploy_to_hf.sh echo_env --dry-run - -# Verify the staging directory was created -ls -la hf-staging/ - -# Check the generated files -tree hf-staging/ -L 3 -``` - -**What to verify:** -- ✅ Staging directory created at `hf-staging//` -- ✅ `Dockerfile` exists and looks correct -- ✅ `README.md` exists with correct metadata -- ✅ `src/core/` and `src/envs//` are copied correctly -- ✅ No deployment attempted (no HF API calls) - -### 2. Test with Test Namespace - -Deploy to your personal test space: - -```bash -# Use your HF username and add -test suffix to avoid affecting production -./scripts/deploy_to_hf.sh echo_env \ - --hf-namespace $(hf auth whoami | head -n1) \ - --space-suffix -test - -# Or use positional arguments -./scripts/deploy_to_hf.sh echo_env "" "$(hf auth whoami | head -n1)" -``` - -**What to verify:** -- ✅ Space created at `https://huggingface.co/spaces//echo_env-test` -- ✅ Files uploaded correctly -- ✅ Space builds successfully (check Space logs) - -### 3. Test Different Environments - -```bash -# Test smallest environment first (echo_env) -./scripts/deploy_to_hf.sh echo_env --dry-run - -# Test with specific base image SHA -./scripts/deploy_to_hf.sh echo_env --base-sha abc123 --dry-run - -# Test other environments -./scripts/deploy_to_hf.sh coding_env --dry-run -./scripts/deploy_to_hf.sh chat_env --dry-run -``` - -### 4. Validate Generated Files - -After dry-run, inspect the generated files: - -```bash -# Check Dockerfile -cat hf-staging//echo_env/Dockerfile - -# Check README -cat hf-staging//echo_env/README.md - -# Verify structure -find hf-staging//echo_env -type f -``` - -## GitHub Actions Testing - -### 0. Do I Need to Merge to Main? - -**No!** You can test from any branch: - -**Option A: Test from feature branch** -1. Push your changes (including workflow file) to your branch -2. Go to GitHub → Actions tab -3. Use the branch dropdown to select your branch -4. Find "Deploy to Hugging Face Environment" workflow -5. Click "Run workflow" → Select your branch → Run - -**Option B: Merge to main first** (easier to find) -- Workflows are most visible from the default branch -- After merge, they're easier to access in the Actions tab - -**Recommendation:** Test locally first, then test from your branch before merging. - -### 1. Manual Workflow Dispatch - -1. Go to GitHub → Actions → "Deploy to Hugging Face Environment" -2. Click "Run workflow" -3. Select: - - Environment: `echo_env` (start with smallest) - - Base image SHA: Leave empty (or test with specific SHA) -4. Click "Run workflow" - -**What to verify:** -- ✅ Workflow runs without errors -- ✅ HF CLI installs correctly -- ✅ Script executes successfully -- ✅ Space deployed to `openenv/echo_env` - -### 2. Test All Environments (Matrix) - -1. Run workflow with environment: `all` -2. This will deploy all environments in parallel -3. Monitor all matrix jobs - -### 3. Test Automatic Trigger - -Make a change to trigger automatic deployment: - -```bash -# Make a small change to core -echo "# Test" >> src/core/client_types.py -git add src/core/client_types.py -git commit -m "test: trigger deployment" -git push -``` - -**What to verify:** -- ✅ Workflow triggers automatically -- ✅ All environments deploy (because core changed) -- ✅ Only changed environments deploy (if only one env changed) - -### 4. Check Workflow Logs - -After workflow runs: -1. Click on the workflow run -2. Check each job's logs -3. Verify: - - ✅ HF CLI installation succeeded - - ✅ Script executed without errors - - ✅ Deployment succeeded - - ✅ Space URL printed at end - -## Verification Checklist - -### After Local Dry-Run -- [ ] Staging directory structure correct -- [ ] Dockerfile uses correct base image -- [ ] README.md has correct metadata -- [ ] All source files copied -- [ ] No sensitive files included - -### After Local Deployment -- [ ] Space appears on Hugging Face -- [ ] Space builds successfully (check build logs) -- [ ] Space is accessible via web UI -- [ ] API endpoints respond correctly - -### After GitHub Actions Deployment -- [ ] All matrix jobs succeeded -- [ ] Spaces deployed to correct namespace (`openenv/`) -- [ ] Spaces build successfully -- [ ] No authentication errors -- [ ] Script output shows success message - -## Common Issues & Debugging - -### Issue: "hf CLI not found" -```bash -# Install HF CLI locally -curl -LsSf https://hf.co/cli/install.sh | sh -# Reload shell or add to PATH -export PATH="$HOME/.local/bin:$PATH" -``` - -### Issue: "Authentication failed" -```bash -# Authenticate -hf auth login -# Or set token -export HF_TOKEN=your_token_here -``` - -### Issue: "Namespace access denied" -- Verify your HF token has access to the target namespace -- For org namespaces, token needs org permissions -- Check: `hf auth whoami` - -### Issue: "Script fails in GitHub Actions" -1. Check if `HF_TOKEN` secret is set in repository settings -2. Verify token has correct permissions (write access to spaces) -3. Check workflow logs for detailed error messages - -## Testing Checklist - -Before merging: -- [ ] Local dry-run works for all environments -- [ ] Local deployment works to test namespace -- [ ] GitHub Actions workflow runs successfully -- [ ] At least one environment deployed via CI -- [ ] Deployed space builds and runs correctly - From f0c12edd7b4e2618ad8ef050856dd8d67cea0063 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 09:45:19 +0100 Subject: [PATCH 15/28] update script to work with arg tokens --- scripts/deploy_to_hf.sh | 65 +++++++++++++++++++++-------------------- 1 file changed, 33 insertions(+), 32 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 5f1a93e4..0e59fe13 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -505,47 +505,47 @@ fi echo "🔑 Ensuring Hugging Face authentication..." -# In GitHub Actions, explicitly authenticate with token +# Set up authentication based on environment +TOKEN_ARGS=() if [ "$IS_GITHUB_ACTIONS" = true ]; then if [ -z "${HF_TOKEN:-}" ]; then echo "Error: HF_TOKEN secret is required in GitHub Actions" >&2 echo "Please set the HF_TOKEN secret in repository settings" >&2 exit 1 fi - echo "Authenticating with HF_TOKEN..." - LOGIN_OUTPUT=$(hf auth login --token "$HF_TOKEN" 2>&1) - LOGIN_EXIT_CODE=$? - if [ $LOGIN_EXIT_CODE -ne 0 ]; then - echo "Error: Failed to authenticate with HF_TOKEN" >&2 - echo "$LOGIN_OUTPUT" >&2 - exit 1 - fi + echo "Using HF_TOKEN from GitHub Actions environment" + # In CI, pass token directly to commands via --token flag + TOKEN_ARGS=(--token "$HF_TOKEN") elif [ -n "${HF_TOKEN:-}" ]; then - # In local environment, try to use HF_TOKEN if set - hf auth login --token "$HF_TOKEN" --add-to-git-credential >/dev/null 2>&1 || true -fi - -# In interactive mode (not CI), ask user to login if needed -if [ "$IS_GITHUB_ACTIONS" != true ] && ! hf auth whoami >/dev/null 2>&1; then - echo "Not authenticated. Please login to Hugging Face..." - hf auth login + # If HF_TOKEN is set locally, use it + echo "Using HF_TOKEN environment variable" + TOKEN_ARGS=(--token "$HF_TOKEN") +else + # Interactive mode: check if user is authenticated + if ! hf auth whoami >/dev/null 2>&1; then + echo "Not authenticated. Please login to Hugging Face..." + hf auth login + if ! hf auth whoami >/dev/null 2>&1; then + echo "Error: Hugging Face authentication failed" >&2 + exit 1 + fi + fi fi -# Verify authentication -if ! hf auth whoami >/dev/null 2>&1; then - echo "Error: Hugging Face authentication failed" >&2 - if [ "$IS_GITHUB_ACTIONS" = true ]; then - echo "Ensure HF_TOKEN secret is set in GitHub Actions" >&2 - else +# Verify authentication works (skip in CI if using token directly) +if [ ${#TOKEN_ARGS[@]} -eq 0 ]; then + if ! hf auth whoami >/dev/null 2>&1; then + echo "Error: Not authenticated with Hugging Face" >&2 echo "Run 'hf auth login' or set HF_TOKEN environment variable" >&2 + exit 1 fi - exit 1 -fi - -CURRENT_USER=$(hf auth whoami | head -n1 | tr -d '\n') -if [ "$CURRENT_USER" != "$HF_NAMESPACE" ] && ! hf auth whoami | grep -qw "$HF_NAMESPACE" 2>/dev/null; then - echo "Warning: Your account ($CURRENT_USER) may not have direct access to namespace '$HF_NAMESPACE'." >&2 - echo "Get the correct access token from https://huggingface.co/settings/tokens and set if with 'hf auth login' " >&2 + CURRENT_USER=$(hf auth whoami | head -n1 | tr -d '\n') + echo "✅ Authenticated as: $CURRENT_USER" + if [ "$CURRENT_USER" != "$HF_NAMESPACE" ]; then + echo "âš ī¸ Deploying to namespace '$HF_NAMESPACE' (different from your user '$CURRENT_USER')" + fi +else + echo "✅ Token configured for deployment" fi SPACE_REPO="${HF_NAMESPACE}/${ENV_NAME}${SPACE_SUFFIX}" @@ -558,9 +558,10 @@ if [ "$PRIVATE" = true ]; then fi # create the space if it doesn't exist -hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG --quiet >/dev/null 2>&1 || true +hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} --quiet >/dev/null 2>&1 || true + # upload the staged content (if repo doesn't exist, it will be created with the privacy setting) -SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space $PRIVATE_FLAG --quiet "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS") +SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} --quiet "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS" 2>&1) if [ $? -ne 0 ]; then echo "❌ Upload failed: $SPACE_UPLOAD_RESULT" >&2 exit 1 From 554159b7ff90da2a18fa2eb8338f6750912d451f Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 09:54:04 +0100 Subject: [PATCH 16/28] log spac creation errors --- scripts/deploy_to_hf.sh | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 0e59fe13..1c91965a 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -558,12 +558,21 @@ if [ "$PRIVATE" = true ]; then fi # create the space if it doesn't exist -hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} --quiet >/dev/null 2>&1 || true +CREATE_OUTPUT=$(hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} 2>&1) +CREATE_EXIT_CODE=$? +if [ $CREATE_EXIT_CODE -ne 0 ]; then + echo "âš ī¸ Space creation returned non-zero exit code" >&2 + echo "$CREATE_OUTPUT" >&2 + # Continue anyway - space might already exist +fi # upload the staged content (if repo doesn't exist, it will be created with the privacy setting) -SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} --quiet "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS" 2>&1) -if [ $? -ne 0 ]; then - echo "❌ Upload failed: $SPACE_UPLOAD_RESULT" >&2 +SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS" 2>&1) +UPLOAD_EXIT_CODE=$? +if [ $UPLOAD_EXIT_CODE -ne 0 ]; then + echo "❌ Upload failed with exit code $UPLOAD_EXIT_CODE" >&2 + echo "Error output:" >&2 + echo "$SPACE_UPLOAD_RESULT" >&2 exit 1 fi # print the URL of the deployed space From a8e81fe753c628361fc5d72edb2247734658fc3f Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 10:01:29 +0100 Subject: [PATCH 17/28] add more logging --- scripts/deploy_to_hf.sh | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 1c91965a..07748b1a 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -549,6 +549,12 @@ else fi SPACE_REPO="${HF_NAMESPACE}/${ENV_NAME}${SPACE_SUFFIX}" + +# Get absolute path to staging directory +if [ ! -d "$CURRENT_STAGING_DIR" ]; then + echo "Error: Staging directory not found: $CURRENT_STAGING_DIR" >&2 + exit 1 +fi CURRENT_STAGING_DIR_ABS=$(cd "$CURRENT_STAGING_DIR" && pwd) # Determine privacy flag (only add --private if needed, default is public) @@ -573,6 +579,12 @@ if [ $UPLOAD_EXIT_CODE -ne 0 ]; then echo "❌ Upload failed with exit code $UPLOAD_EXIT_CODE" >&2 echo "Error output:" >&2 echo "$SPACE_UPLOAD_RESULT" >&2 + echo "" >&2 + echo "Debug info:" >&2 + echo " Space: $SPACE_REPO" >&2 + echo " Staging dir: $CURRENT_STAGING_DIR_ABS" >&2 + echo " Files to upload:" >&2 + ls -la "$CURRENT_STAGING_DIR_ABS" >&2 || true exit 1 fi # print the URL of the deployed space From 36875571ee5d29cf50235bac750820c2730c6ad5 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 10:07:35 +0100 Subject: [PATCH 18/28] even more logging --- scripts/deploy_to_hf.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 07748b1a..63d6ee88 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -563,6 +563,8 @@ if [ "$PRIVATE" = true ]; then PRIVATE_FLAG="--private" fi +echo "Creating space: $SPACE_REPO" +echo "Command: hf repo create $SPACE_REPO --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"}" # create the space if it doesn't exist CREATE_OUTPUT=$(hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} 2>&1) CREATE_EXIT_CODE=$? @@ -572,6 +574,8 @@ if [ $CREATE_EXIT_CODE -ne 0 ]; then # Continue anyway - space might already exist fi +echo "Uploading files to space: $SPACE_REPO" +echo "Command: hf upload --repo-type=space $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} $SPACE_REPO $CURRENT_STAGING_DIR_ABS" # upload the staged content (if repo doesn't exist, it will be created with the privacy setting) SPACE_UPLOAD_RESULT=$(hf upload --repo-type=space $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} "$SPACE_REPO" "$CURRENT_STAGING_DIR_ABS" 2>&1) UPLOAD_EXIT_CODE=$? From ae7c547ff13936266c602ffe4600c5efc68f9b80 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 10:14:11 +0100 Subject: [PATCH 19/28] add optional namespace to env --- .github/workflows/deploy-hf-env.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index eabd2382..8ba42d9a 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -124,7 +124,7 @@ jobs: - name: Deploy to Hugging Face Space env: HF_TOKEN: ${{ secrets.HF_TOKEN }} - HF_NAMESPACE: ${{ env.HF_USERNAME }} + HF_NAMESPACE: ${{ github.event.inputs.hf_namespace || env.HF_USERNAME }} run: | chmod +x scripts/deploy_to_hf.sh if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then @@ -156,7 +156,7 @@ jobs: - name: Deploy to Hugging Face Space env: HF_TOKEN: ${{ secrets.HF_TOKEN }} - HF_NAMESPACE: ${{ env.HF_USERNAME }} + HF_NAMESPACE: ${{ github.event.inputs.hf_namespace || env.HF_USERNAME }} run: | chmod +x scripts/deploy_to_hf.sh if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then From d06174cabd6c38cddae365bf8370779c0a94d283 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 17:59:40 +0100 Subject: [PATCH 20/28] expose logging --- .github/workflows/deploy-hf-env.yml | 2 +- scripts/deploy_to_hf.sh | 18 ++++++++++++++++-- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index 8ba42d9a..2439b8c7 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -37,7 +37,7 @@ on: default: '' env: - HF_USERNAME: openenv + HF_USERNAME: openenv-testing jobs: # Job to determine which environments to deploy diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 63d6ee88..f8edb930 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -566,12 +566,26 @@ fi echo "Creating space: $SPACE_REPO" echo "Command: hf repo create $SPACE_REPO --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"}" # create the space if it doesn't exist +# Temporarily disable exit-on-error for this command +set +e CREATE_OUTPUT=$(hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} 2>&1) CREATE_EXIT_CODE=$? +set -e if [ $CREATE_EXIT_CODE -ne 0 ]; then - echo "âš ī¸ Space creation returned non-zero exit code" >&2 + echo "❌ Space creation failed with exit code $CREATE_EXIT_CODE" >&2 + echo "Error output:" >&2 echo "$CREATE_OUTPUT" >&2 - # Continue anyway - space might already exist + echo "" >&2 + echo "Possible causes:" >&2 + echo " 1. Token doesn't have write access to namespace '$HF_NAMESPACE'" >&2 + echo " 2. Token doesn't have permission to create spaces in this organization" >&2 + echo " 3. Organization '$HF_NAMESPACE' doesn't exist or isn't accessible" >&2 + echo "" >&2 + echo "To fix:" >&2 + echo " 1. Verify you have access to https://huggingface.co/$HF_NAMESPACE" >&2 + echo " 2. Ensure HF_TOKEN has 'write' role (not just 'read')" >&2 + echo " 3. For organization namespaces, token must have org member/write access" >&2 + exit 1 fi echo "Uploading files to space: $SPACE_REPO" From 929cc88954ac6c5f506ae99e11e15c8eb4ef0e3f Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:03:39 +0100 Subject: [PATCH 21/28] fix space sdk --- scripts/deploy_to_hf.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index f8edb930..42dc80cd 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -564,11 +564,11 @@ if [ "$PRIVATE" = true ]; then fi echo "Creating space: $SPACE_REPO" -echo "Command: hf repo create $SPACE_REPO --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"}" +echo "Command: hf repo create $SPACE_REPO --repo-type space --space-sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"}" # create the space if it doesn't exist # Temporarily disable exit-on-error for this command set +e -CREATE_OUTPUT=$(hf repo create "$SPACE_REPO" --repo-type space --space_sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} 2>&1) +CREATE_OUTPUT=$(hf repo create "$SPACE_REPO" --repo-type space --space-sdk docker --exist-ok $PRIVATE_FLAG ${TOKEN_ARGS[@]+"${TOKEN_ARGS[@]}"} 2>&1) CREATE_EXIT_CODE=$? set -e if [ $CREATE_EXIT_CODE -ne 0 ]; then From e5fd589d93645314f68b667ea4b59221acc1a81d Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:06:14 +0100 Subject: [PATCH 22/28] tidy logging and working on fork with gh action --- scripts/deploy_to_hf.sh | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index 42dc80cd..db1272bf 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -576,16 +576,6 @@ if [ $CREATE_EXIT_CODE -ne 0 ]; then echo "Error output:" >&2 echo "$CREATE_OUTPUT" >&2 echo "" >&2 - echo "Possible causes:" >&2 - echo " 1. Token doesn't have write access to namespace '$HF_NAMESPACE'" >&2 - echo " 2. Token doesn't have permission to create spaces in this organization" >&2 - echo " 3. Organization '$HF_NAMESPACE' doesn't exist or isn't accessible" >&2 - echo "" >&2 - echo "To fix:" >&2 - echo " 1. Verify you have access to https://huggingface.co/$HF_NAMESPACE" >&2 - echo " 2. Ensure HF_TOKEN has 'write' role (not just 'read')" >&2 - echo " 3. For organization namespaces, token must have org member/write access" >&2 - exit 1 fi echo "Uploading files to space: $SPACE_REPO" @@ -598,7 +588,6 @@ if [ $UPLOAD_EXIT_CODE -ne 0 ]; then echo "Error output:" >&2 echo "$SPACE_UPLOAD_RESULT" >&2 echo "" >&2 - echo "Debug info:" >&2 echo " Space: $SPACE_REPO" >&2 echo " Staging dir: $CURRENT_STAGING_DIR_ABS" >&2 echo " Files to upload:" >&2 From d6f006d3d6ad0a49795e9a7da75e3840b357db83 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:07:13 +0100 Subject: [PATCH 23/28] remove testing from env variable --- .github/workflows/deploy-hf-env.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index 2439b8c7..8ba42d9a 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -37,7 +37,7 @@ on: default: '' env: - HF_USERNAME: openenv-testing + HF_USERNAME: openenv jobs: # Job to determine which environments to deploy From f2b00551b88cfc5644a6586146a48bc1e8a34065 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:11:46 +0100 Subject: [PATCH 24/28] lose general env variable --- .github/workflows/deploy-hf-env.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index 8ba42d9a..93fd5939 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -36,9 +36,6 @@ on: type: string default: '' -env: - HF_USERNAME: openenv - jobs: # Job to determine which environments to deploy determine-environments: @@ -124,7 +121,8 @@ jobs: - name: Deploy to Hugging Face Space env: HF_TOKEN: ${{ secrets.HF_TOKEN }} - HF_NAMESPACE: ${{ github.event.inputs.hf_namespace || env.HF_USERNAME }} + HF_NAMESPACE: ${{ github.event.inputs.hf_namespace }} + HF_USERNAME: ${{ github.event.inputs.hf_namespace }} run: | chmod +x scripts/deploy_to_hf.sh if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then @@ -156,7 +154,8 @@ jobs: - name: Deploy to Hugging Face Space env: HF_TOKEN: ${{ secrets.HF_TOKEN }} - HF_NAMESPACE: ${{ github.event.inputs.hf_namespace || env.HF_USERNAME }} + HF_NAMESPACE: ${{ github.event.inputs.hf_namespace }} + HF_USERNAME: ${{ github.event.inputs.hf_namespace }} run: | chmod +x scripts/deploy_to_hf.sh if [ -n "${{ github.event.inputs.base_image_sha }}" ]; then From 2278a392f12a3312d04ed33ecda337d304baf6dd Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:31:24 +0100 Subject: [PATCH 25/28] add custom environment feature --- .github/workflows/deploy-hf-env.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/deploy-hf-env.yml b/.github/workflows/deploy-hf-env.yml index 93fd5939..d84833df 100644 --- a/.github/workflows/deploy-hf-env.yml +++ b/.github/workflows/deploy-hf-env.yml @@ -15,6 +15,11 @@ on: - 'chat_env' - 'atari_env' - 'openspiel_env' + custom_environment: + description: 'Custom environment to deploy (leave empty for none)' + required: false + type: string + default: '' base_image_sha: description: 'SHA for openenv-base image (leave empty for latest)' required: false From d0c349b831ae5f013736c020afc36abb7894fbf4 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:35:06 +0100 Subject: [PATCH 26/28] remove excess copy --- scripts/deploy_to_hf.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index db1272bf..e0d0a06e 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -256,9 +256,6 @@ COPY src/core/ /app/src/core/ # Copy OpenSpiel environment COPY src/envs/openspiel_env/ /app/src/envs/openspiel_env/ -# Copy README for web interface documentation -COPY src/envs/openspiel_env/README.md /app/README.md - # Extend Python path for OpenEnv (base image set PYTHONPATH=/app/src) # We prepend OpenSpiel paths ENV PYTHONPATH=/repo:/repo/build/python:/app/src From 3ab76e949a67c93263f7e24c644f94fba9c143a9 Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:41:40 +0100 Subject: [PATCH 27/28] copy inits --- scripts/deploy_to_hf.sh | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index e0d0a06e..b21fa64a 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -172,10 +172,20 @@ CURRENT_STAGING_DIR="${STAGING_DIR}/${HF_NAMESPACE}/${ENV_NAME}" mkdir -p "$CURRENT_STAGING_DIR/src/core" mkdir -p "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME" +# Copy src/__init__.py if it exists +if [ -f "src/__init__.py" ]; then + cp src/__init__.py "$CURRENT_STAGING_DIR/src/__init__.py" +fi + # Copy core files cp -R src/core/ "$CURRENT_STAGING_DIR/src/core/" + # Copy environment files cp -R "src/envs/$ENV_NAME/" "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME/" + +# Create __init__.py for envs package (needed for Python imports) +touch "$CURRENT_STAGING_DIR/src/envs/__init__.py" + echo "📁 Copied core and $ENV_NAME environment files to $CURRENT_STAGING_DIR" # Create environment-specific multi-stage Dockerfile From 1a1f2f976561bcedcea570bbb0c619116b82f74f Mon Sep 17 00:00:00 2001 From: burtenshaw Date: Fri, 31 Oct 2025 21:57:07 +0100 Subject: [PATCH 28/28] fix copy --- scripts/deploy_to_hf.sh | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/scripts/deploy_to_hf.sh b/scripts/deploy_to_hf.sh index b21fa64a..b3545669 100755 --- a/scripts/deploy_to_hf.sh +++ b/scripts/deploy_to_hf.sh @@ -169,22 +169,16 @@ fi # Create staging directory CURRENT_STAGING_DIR="${STAGING_DIR}/${HF_NAMESPACE}/${ENV_NAME}" +# Ensure clean staging directory +rm -rf "$CURRENT_STAGING_DIR" mkdir -p "$CURRENT_STAGING_DIR/src/core" mkdir -p "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME" -# Copy src/__init__.py if it exists -if [ -f "src/__init__.py" ]; then - cp src/__init__.py "$CURRENT_STAGING_DIR/src/__init__.py" -fi - # Copy core files -cp -R src/core/ "$CURRENT_STAGING_DIR/src/core/" +cp -R src/core/* "$CURRENT_STAGING_DIR/src/core/" # Copy environment files -cp -R "src/envs/$ENV_NAME/" "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME/" - -# Create __init__.py for envs package (needed for Python imports) -touch "$CURRENT_STAGING_DIR/src/envs/__init__.py" +cp -R src/envs/$ENV_NAME/* "$CURRENT_STAGING_DIR/src/envs/$ENV_NAME/" echo "📁 Copied core and $ENV_NAME environment files to $CURRENT_STAGING_DIR"