Spaces:
Build error
Build error
Remove database
Browse files- app.py +4 -7
- database.py +0 -75
- ui.py +25 -67
app.py
CHANGED
@@ -20,7 +20,6 @@ from gradio_webhooks import GradioWebhookApp, WebhookPayload
|
|
20 |
from huggingface_hub import login
|
21 |
from huggingface_hub.utils import RepositoryNotFoundError
|
22 |
from ui import generate_ui
|
23 |
-
from database import is_space_registered
|
24 |
|
25 |
login(token=os.getenv("HF_TOKEN"))
|
26 |
|
@@ -35,8 +34,6 @@ async def post_webhook(payload: WebhookPayload, task_queue: BackgroundTasks):
|
|
35 |
raise HTTPException(400, f"Must be a Space, not {payload.repo.type}")
|
36 |
|
37 |
space_id = payload.repo.name
|
38 |
-
if not is_space_registered(space_id):
|
39 |
-
return "Space not in the watchlist."
|
40 |
|
41 |
has_task = False
|
42 |
if (
|
@@ -97,7 +94,7 @@ async def post_webhook(payload: WebhookPayload, task_queue: BackgroundTasks):
|
|
97 |
"Task scheduled to sync/delete Space", status_code=status.HTTP_202_ACCEPTED
|
98 |
)
|
99 |
else:
|
100 |
-
return Response("No task scheduled", status_code=status.
|
101 |
|
102 |
|
103 |
def is_pr_synced(space_id: str, pr_num: int) -> bool:
|
@@ -214,19 +211,19 @@ Following the creation of this PR, an ephemeral Space [{ci_space_id}](https://hu
|
|
214 |
|
215 |
If your Space requires configuration (secrets or upgraded hardware), you must duplicate the ephemeral Space to your account and configure the settings by yourself. You are responsible of making sure that the changes introduced in the PR are not harmful (leak secrets, run malicious scripts,...).
|
216 |
|
217 |
-
_(This is an automated message.
|
218 |
"""
|
219 |
|
220 |
NOTIFICATION_TEMPLATE_UPDATE = """\
|
221 |
Following new commits that happened in this PR, the ephemeral Space [{ci_space_id}](https://huggingface.co/spaces/{ci_space_id}) has been updated.
|
222 |
|
223 |
-
_(This is an automated message.
|
224 |
"""
|
225 |
|
226 |
NOTIFICATION_TEMPLATE_DELETE = """\
|
227 |
PR is now merged/closed. The ephemeral Space has been deleted.
|
228 |
|
229 |
-
_(This is an automated message.
|
230 |
"""
|
231 |
|
232 |
|
|
|
20 |
from huggingface_hub import login
|
21 |
from huggingface_hub.utils import RepositoryNotFoundError
|
22 |
from ui import generate_ui
|
|
|
23 |
|
24 |
login(token=os.getenv("HF_TOKEN"))
|
25 |
|
|
|
34 |
raise HTTPException(400, f"Must be a Space, not {payload.repo.type}")
|
35 |
|
36 |
space_id = payload.repo.name
|
|
|
|
|
37 |
|
38 |
has_task = False
|
39 |
if (
|
|
|
94 |
"Task scheduled to sync/delete Space", status_code=status.HTTP_202_ACCEPTED
|
95 |
)
|
96 |
else:
|
97 |
+
return Response("No task scheduled", status_code=status.HTTP_200_OK)
|
98 |
|
99 |
|
100 |
def is_pr_synced(space_id: str, pr_num: int) -> bool:
|
|
|
211 |
|
212 |
If your Space requires configuration (secrets or upgraded hardware), you must duplicate the ephemeral Space to your account and configure the settings by yourself. You are responsible of making sure that the changes introduced in the PR are not harmful (leak secrets, run malicious scripts,...).
|
213 |
|
214 |
+
_(This is an automated message.)_
|
215 |
"""
|
216 |
|
217 |
NOTIFICATION_TEMPLATE_UPDATE = """\
|
218 |
Following new commits that happened in this PR, the ephemeral Space [{ci_space_id}](https://huggingface.co/spaces/{ci_space_id}) has been updated.
|
219 |
|
220 |
+
_(This is an automated message.)_
|
221 |
"""
|
222 |
|
223 |
NOTIFICATION_TEMPLATE_DELETE = """\
|
224 |
PR is now merged/closed. The ephemeral Space has been deleted.
|
225 |
|
226 |
+
_(This is an automated message.)_
|
227 |
"""
|
228 |
|
229 |
|
database.py
DELETED
@@ -1,75 +0,0 @@
|
|
1 |
-
from huggingface_hub import hf_hub_download, upload_file, space_info
|
2 |
-
from huggingface_hub.utils import HfHubHTTPError
|
3 |
-
from pathlib import Path
|
4 |
-
from typing import Set
|
5 |
-
|
6 |
-
DATABASE_REPO_ID = "spaces-ci-bot/webhook"
|
7 |
-
DATABASE_FILE = "registered_spaces.txt"
|
8 |
-
|
9 |
-
MAX_NB_ATTEMPTS = 10
|
10 |
-
|
11 |
-
|
12 |
-
def is_space_existing(space_id: str) -> bool:
|
13 |
-
try:
|
14 |
-
space_info(repo_id=space_id)
|
15 |
-
return True
|
16 |
-
except HfHubHTTPError:
|
17 |
-
return False
|
18 |
-
|
19 |
-
|
20 |
-
def is_space_registered(space_id: str) -> bool:
|
21 |
-
return space_id in get_registered_spaces()
|
22 |
-
|
23 |
-
|
24 |
-
def get_registered_spaces() -> Set[str]:
|
25 |
-
return _read_database(_get_latest_file())
|
26 |
-
|
27 |
-
|
28 |
-
def update_status(space_id: str, should_watch: bool) -> None:
|
29 |
-
nb_attempts = 0
|
30 |
-
while True:
|
31 |
-
# Get registered spaces
|
32 |
-
filepath = _get_latest_file()
|
33 |
-
registered_spaces = _read_database(filepath)
|
34 |
-
|
35 |
-
# Do nothing if:
|
36 |
-
# - need to register and already registered
|
37 |
-
# - need to unregister and already not registered
|
38 |
-
if (should_watch and space_id in registered_spaces) or (
|
39 |
-
not should_watch and space_id not in registered_spaces
|
40 |
-
):
|
41 |
-
return
|
42 |
-
|
43 |
-
# Else, (un)register new space
|
44 |
-
latest_revision = filepath.parent.name
|
45 |
-
if should_watch:
|
46 |
-
registered_spaces.add(space_id)
|
47 |
-
else:
|
48 |
-
registered_spaces.remove(space_id)
|
49 |
-
|
50 |
-
# Re-upload database and ensure no concurrent call happened
|
51 |
-
try:
|
52 |
-
nb_attempts += 1
|
53 |
-
upload_file(
|
54 |
-
path_in_repo=DATABASE_FILE,
|
55 |
-
repo_id=DATABASE_REPO_ID,
|
56 |
-
repo_type="dataset",
|
57 |
-
path_or_fileobj="\n".join(sorted(registered_spaces)).encode(),
|
58 |
-
commit_message=(
|
59 |
-
f"Register {space_id}" if should_watch else f"Unregister {space_id}"
|
60 |
-
),
|
61 |
-
parent_commit=latest_revision, # ensure consistency
|
62 |
-
)
|
63 |
-
return
|
64 |
-
except HfHubHTTPError:
|
65 |
-
# Retry X times before giving up (in case multiple registrations at the same time)
|
66 |
-
if nb_attempts == MAX_NB_ATTEMPTS:
|
67 |
-
raise
|
68 |
-
|
69 |
-
|
70 |
-
def _read_database(filepath: Path) -> Set[str]:
|
71 |
-
return set(filepath.read_text().split())
|
72 |
-
|
73 |
-
|
74 |
-
def _get_latest_file() -> Path:
|
75 |
-
return Path(hf_hub_download(DATABASE_REPO_ID, DATABASE_FILE, repo_type="dataset"))
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ui.py
CHANGED
@@ -1,82 +1,40 @@
|
|
1 |
import gradio as gr
|
2 |
-
from enum import Enum
|
3 |
-
from database import is_space_existing, is_space_registered, update_status
|
4 |
|
5 |
|
6 |
TITLE = "βοΈ Spaces CI Bot βοΈ"
|
|
|
7 |
DESCRIPTION = """
|
8 |
-
Welcome
|
9 |
|
10 |
-
|
11 |
-
deleted.
|
12 |
|
13 |
-
|
14 |
-
"""
|
15 |
|
|
|
|
|
|
|
|
|
|
|
16 |
|
17 |
-
|
18 |
-
REGISTER = "Enable CI Bot"
|
19 |
-
UNREGISTER = "Disable CI Bot"
|
20 |
-
CHECK_STATUS = "Check status"
|
21 |
|
|
|
|
|
|
|
|
|
|
|
22 |
|
23 |
-
|
24 |
-
if not is_space_existing(space_id):
|
25 |
-
return f"""## Error
|
26 |
-
Could not find Space '**{space_id}**' on the Hub.
|
27 |
-
Please make sure you are trying to register a public repository.
|
28 |
-
"""
|
29 |
|
30 |
-
|
31 |
-
|
32 |
-
|
33 |
-
|
34 |
-
The Space '**{space_id}**' is already in the watchlist. Any PR opened on
|
35 |
-
this repository will trigger an ephemeral Space.
|
36 |
-
"""
|
37 |
-
else:
|
38 |
-
update_status(space_id, should_watch=True)
|
39 |
-
return f"""## Success
|
40 |
-
The Space '**{space_id}**' has been added to the watchlist. Any PR opened on
|
41 |
-
this repository will trigger an ephemeral Space.
|
42 |
-
"""
|
43 |
-
elif action == Action.UNREGISTER.value:
|
44 |
-
if not registered:
|
45 |
-
return f"""## Did nothing
|
46 |
-
The Space '**{space_id}**' is currently not in the watchlist.
|
47 |
-
"""
|
48 |
-
else:
|
49 |
-
update_status(space_id, should_watch=False)
|
50 |
-
return f"""## Success
|
51 |
-
The Space '**{space_id}**' has been removed from the watchlist.
|
52 |
-
"""
|
53 |
-
elif action == Action.CHECK_STATUS.value:
|
54 |
-
if registered:
|
55 |
-
return f"""## Watched
|
56 |
-
The Space '**{space_id}**' is already in the watchlist. Any PR opened on
|
57 |
-
this repository will trigger an ephemeral Space.
|
58 |
-
"""
|
59 |
-
else:
|
60 |
-
return f"""## Not watched
|
61 |
-
The Space '**{space_id}**' is currently not in the watchlist.
|
62 |
-
"""
|
63 |
-
else:
|
64 |
-
return f"**Error:** action {action} not implemented."
|
65 |
|
66 |
|
67 |
def generate_ui() -> gr.Blocks:
|
68 |
-
|
69 |
-
|
70 |
-
|
71 |
-
|
72 |
-
|
73 |
-
[action.value for action in Action],
|
74 |
-
value=Action.REGISTER.value,
|
75 |
-
label="What should I do?",
|
76 |
-
),
|
77 |
-
],
|
78 |
-
outputs=[gr.Markdown()],
|
79 |
-
title=TITLE,
|
80 |
-
description=DESCRIPTION,
|
81 |
-
allow_flagging="never",
|
82 |
-
)
|
|
|
1 |
import gradio as gr
|
|
|
|
|
2 |
|
3 |
|
4 |
TITLE = "βοΈ Spaces CI Bot βοΈ"
|
5 |
+
|
6 |
DESCRIPTION = """
|
7 |
+
Welcome to the Spaces CI Bot!
|
8 |
|
9 |
+
You are a few clicks away from having the CI Bot configured on your Spaces. No code or maintenance is required: simply configure a webhook and you're done! π
|
|
|
10 |
|
11 |
+
## Things to know
|
|
|
12 |
|
13 |
+
- You can enable the CI Bot for a single Space or globally for all Spaces of a user/organization. You do not need to own the Space to enable the CI Bot on it.
|
14 |
+
- When a PR is opened on a watched Space, an ephemeral Space is deployed with the changes.
|
15 |
+
- Any changes pushed to a PR will trigger a re-deployment. Once the PR is merged, the ephemeral Space is deleted.
|
16 |
+
- If your Space requires configuration (secrets or upgraded hardware), you must duplicate the ephemeral Space to your account and configure the settings by yourself. You are responsible of making sure that the changes introduced in the PR are not harmful (leak secrets, run malicious scripts,...).
|
17 |
+
- The Bot is still in beta. Feel free to give us feedback in the [Community tab](https://huggingface.co/datasets/spaces-ci-bot/webhook/discussions).
|
18 |
|
19 |
+
## Instructions
|
|
|
|
|
|
|
20 |
|
21 |
+
#### 1. Go to your [settings page](https://huggingface.co/settings/webhooks) > "Add a new webhook"
|
22 |
+
#### 2. Configure your webhook (see image below)
|
23 |
+
1. Filter which user, organization or Space you want to watch. It can be a Space you own or not. In this example, all Spaces from `Wauplin` are watched.
|
24 |
+
2. Set the webhook URL to <https://spaces-ci-bot-webhook.hf.space/webhook>.
|
25 |
+
3. Make sure to watch both "repo changes" and "community"
|
26 |
|
27 |
+
![](https://huggingface.co/spaces/spaces-ci-bot/webhook/resolve/main/configure_webhook.jpg)
|
|
|
|
|
|
|
|
|
|
|
28 |
|
29 |
+
#### 3. "Create webhook" > You are done!
|
30 |
+
|
31 |
+
Existing PRs will get an ephemeral Space as soon as you push at least one commit to the repository.
|
32 |
+
"""
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
33 |
|
34 |
|
35 |
def generate_ui() -> gr.Blocks:
|
36 |
+
ui = gr.Blocks()
|
37 |
+
with ui:
|
38 |
+
gr.Markdown(f"<h1 style='text-align: center; margin-bottom: 1rem'>{TITLE}</h1>")
|
39 |
+
gr.Markdown(DESCRIPTION)
|
40 |
+
return ui
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|