Spaces:
Runtime error
Runtime error
File size: 5,537 Bytes
7403ab9 713516b 7403ab9 b23c183 713516b 7403ab9 8e54bfd 7403ab9 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
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.
"""
SUCCESS_MESSAGE = """
### Success 🔥
Yay! A PR has been open to enable Space CI on {space_id}. Check it out here: [{pr_url}]({pr_url}).
You can contact the Space owner to let them know about 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:
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 token + repo existence
try:
user = api.whoami()
if user["type"] != "user":
raise gr.Error(
"You must use a user token, not an organization token. Go to https://huggingface.co/settings/token to create a new token."
)
except Exception as e:
raise gr.Error("Invalid token: {e}") from e
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.1\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 SUCCESS_MESSAGE.format(space_id=space_id, pr_url=commit.pr_url)
|