Spaces:
Runtime error
Runtime error
| import re | |
| import time | |
| import gradio as gr | |
| from huggingface_hub import CommitOperationAdd, HfApi, RepoUrl, SpaceCard | |
| IMPORTS_REGEX = re.compile(r"^(from|import) .*$", re.MULTILINE) | |
| PR_DESCRIPTION = """ | |
| This PR enables Space CI on your Space. **Gradio Space CI is a tool to create ephemeral Spaces for each PR opened on your Space repo.** The goal is to improve developer experience by making the review process as lean as possible. | |
| ### ⚙️ How it works: | |
| - Listens to pull requests events: | |
| - If PR is opened => starts an ephemeral Space | |
| - If PR is updated => updates the Space | |
| - If PR is closed => deleted the Space | |
| - Checks PR author: | |
| - If trusted author => ephemeral Space is configured with variables, secrets and hardware. | |
| - If not a trusted author => ephemeral Space is started without configuration. | |
| - Space owners are trusted by default. Additional "trusted authors" can be configuration manually. | |
| ### ⚠️ Before merging: | |
| 1. Check that the configuration is correct. By default the Space is configured to run ephemeral Spaces on a (free) CPU instance without any secrets. | |
| 2. You must set `HF_TOKEN` as a secret in your Space settings. Token must have 'write' permission. You can create a new one in your [User settings](https://huggingface.co/settings/token). | |
| --- | |
| This is an automated PR created with https://huggingface.co/spaces/Wauplin/gradio-space-ci. | |
| For more details about Space CI, checkout [this page]](https://huggingface.co/spaces/Wauplin/gradio-space-ci/blob/main/README.md). | |
| If you find any issues, please report here: https://huggingface.co/spaces/Wauplin/gradio-space-ci/discussions | |
| Feel free to ignore this PR. | |
| """ | |
| def open_pr(space_id_or_url: str, oauth_token: gr.OAuthToken | None) -> str: | |
| if oauth_token is None: | |
| raise gr.Error("You must be logged in to open a PR. Click on 'Sign in with Huggingface' first.") | |
| token = oauth_token.token | |
| if oauth_token.expires_at < time.time(): | |
| raise gr.Error("Token expired. Logout and try again.") | |
| api = HfApi(token=token) | |
| if not space_id_or_url: | |
| raise gr.Error("You must input a Space ID or URL.") | |
| space_id = ( | |
| RepoUrl(space_id_or_url).repo_id if "https://huggingface.co/spaces/" in space_id_or_url else space_id_or_url | |
| ) | |
| # 0. Check repo existence | |
| if not api.repo_exists(space_id, repo_type="space"): | |
| raise gr.Error(f"Space does not exist: 'https://huggingface.co/spaces/{space_id}'.") | |
| # 1. Add to requirements.txt | |
| if api.file_exists(repo_id=space_id, repo_type="space", filename="requirements.txt"): | |
| requirements_file = api.hf_hub_download(repo_id=space_id, repo_type="space", filename="requirements.txt") | |
| with open(requirements_file) as f: | |
| requirements = f.read() | |
| else: | |
| requirements = "" | |
| if "gradio-space-ci" not in requirements: | |
| requirements += "\ngradio-space-ci @ git+https://huggingface.co/spaces/Wauplin/gradio-space-ci@0.2.3\n" | |
| # 2. Configure CI in README.md | |
| card = SpaceCard.load(api.hf_hub_download(repo_id=space_id, repo_type="space", filename="README.md")) | |
| card.data["space_ci"] = { | |
| "trusted_authors": [], | |
| "secrets": [], | |
| "hardware": "cpu-basic", | |
| "storage": None, | |
| } | |
| if card.data.sdk != "gradio": | |
| raise gr.Error(f"Space must be a Gradio Space, not '{card.data.sdk}'.") | |
| app_file = card.data.app_file | |
| if app_file is None: | |
| raise gr.Error("Space must have an app_file defined their README.") | |
| if not api.file_exists(repo_id=space_id, repo_type="space", filename=app_file): | |
| raise gr.Error(f"Could not find app file '{app_file}' in Space repo.") | |
| # 3. Enable CI in app.py | |
| with open(api.hf_hub_download(repo_id=space_id, repo_type="space", filename=app_file)) as f: | |
| app = f.read() | |
| if "enable_space_ci()" in app: | |
| raise gr.Error("Space CI is already enabled.") | |
| all_imports = list(IMPORTS_REGEX.finditer(app)) | |
| if len(all_imports) == 0: | |
| raise gr.Error("Could not find any imports in app.py.") | |
| last_import = all_imports[-1] | |
| app = ( | |
| app[: last_import.end()] | |
| + "\n\n" | |
| + "from gradio_space_ci import enable_space_ci" | |
| + "\n\n" | |
| + "enable_space_ci()" | |
| + "\n\n" | |
| + app[last_import.end() :] | |
| ) | |
| # 4. Push changes as a PR | |
| commit = api.create_commit( | |
| repo_id=space_id, | |
| repo_type="space", | |
| operations=[ | |
| CommitOperationAdd(path_in_repo="README.md", path_or_fileobj=str(card).encode()), | |
| CommitOperationAdd(path_in_repo="requirements.txt", path_or_fileobj=requirements.encode()), | |
| CommitOperationAdd(path_in_repo=app_file, path_or_fileobj=app.encode()), | |
| ], | |
| commit_message="Enable Space CI", | |
| commit_description=PR_DESCRIPTION, | |
| create_pr=True, | |
| ) | |
| assert commit.pr_url is not None # since `create_pr=True` | |
| return commit.pr_url | |