Spaces:
Build error
Build error
testbot
commited on
Commit
•
a5e8053
1
Parent(s):
8b1b383
Use huggingface_hub.WebhooksServer
Browse files- app.py +5 -5
- gradio_webhooks.py +0 -110
- requirements.txt +2 -2
- simple.py +0 -12
- ui.py +1 -1
app.py
CHANGED
@@ -16,8 +16,8 @@ from huggingface_hub import (
|
|
16 |
)
|
17 |
from huggingface_hub.repocard import RepoCard
|
18 |
from requests import HTTPError
|
19 |
-
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 |
|
@@ -25,11 +25,11 @@ login(token=os.getenv("HF_TOKEN"))
|
|
25 |
|
26 |
CI_BOT_NAME = "spaces-ci-bot"
|
27 |
|
28 |
-
app =
|
29 |
|
30 |
|
31 |
-
@app.add_webhook
|
32 |
-
async def
|
33 |
if payload.repo.type != "space":
|
34 |
raise HTTPException(400, f"Must be a Space, not {payload.repo.type}")
|
35 |
|
@@ -232,4 +232,4 @@ _(This is an automated message.)_
|
|
232 |
"""
|
233 |
|
234 |
|
235 |
-
app.
|
|
|
16 |
)
|
17 |
from huggingface_hub.repocard import RepoCard
|
18 |
from requests import HTTPError
|
|
|
19 |
from huggingface_hub import login
|
20 |
+
from huggingface_hub import WebhooksServer, WebhookPayload
|
21 |
from huggingface_hub.utils import RepositoryNotFoundError
|
22 |
from ui import generate_ui
|
23 |
|
|
|
25 |
|
26 |
CI_BOT_NAME = "spaces-ci-bot"
|
27 |
|
28 |
+
app = WebhooksServer(ui=generate_ui())
|
29 |
|
30 |
|
31 |
+
@app.add_webhook
|
32 |
+
async def trigger_ci_on_pr(payload: WebhookPayload, task_queue: BackgroundTasks):
|
33 |
if payload.repo.type != "space":
|
34 |
raise HTTPException(400, f"Must be a Space, not {payload.repo.type}")
|
35 |
|
|
|
232 |
"""
|
233 |
|
234 |
|
235 |
+
app.run()
|
gradio_webhooks.py
DELETED
@@ -1,110 +0,0 @@
|
|
1 |
-
import os
|
2 |
-
from typing import Literal, Optional, Set
|
3 |
-
|
4 |
-
import gradio as gr
|
5 |
-
from fastapi import Request
|
6 |
-
from fastapi.responses import JSONResponse
|
7 |
-
from pydantic import BaseModel
|
8 |
-
|
9 |
-
|
10 |
-
class GradioWebhookApp:
|
11 |
-
"""
|
12 |
-
```py
|
13 |
-
from gradio_webhooks import GradioWebhookApp
|
14 |
-
|
15 |
-
app = GradioWebhookApp()
|
16 |
-
|
17 |
-
|
18 |
-
@app.add_webhook("/test_webhook")
|
19 |
-
async def hello():
|
20 |
-
return {"in_gradio": True}
|
21 |
-
|
22 |
-
|
23 |
-
app.ready()
|
24 |
-
```
|
25 |
-
"""
|
26 |
-
|
27 |
-
def __init__(
|
28 |
-
self,
|
29 |
-
ui: gr.Blocks,
|
30 |
-
webhook_secret: Optional[str] = None,
|
31 |
-
) -> None:
|
32 |
-
# Launch gradio app:
|
33 |
-
# - as non-blocking so that webhooks can be added afterwards
|
34 |
-
# - as shared if launch locally (to receive webhooks)
|
35 |
-
app, _, _ = ui.launch(prevent_thread_lock=True, share=not ui.is_space)
|
36 |
-
self.gradio_app = ui
|
37 |
-
self.fastapi_app = app
|
38 |
-
self.webhook_paths: Set[str] = set()
|
39 |
-
|
40 |
-
# Add auth middleware to check the "X-Webhook-Secret" header
|
41 |
-
self._webhook_secret = webhook_secret or os.getenv("WEBHOOK_SECRET")
|
42 |
-
if self._webhook_secret is None:
|
43 |
-
print(
|
44 |
-
"\nWebhook secret is not defined. This means your webhook endpoints will be open to everyone."
|
45 |
-
)
|
46 |
-
print(
|
47 |
-
"To add a secret, set `WEBHOOK_SECRET` as environment variable or pass it at initialization: "
|
48 |
-
"\n\t`app = GradioWebhookApp(webhook_secret='my_secret', ...)`"
|
49 |
-
)
|
50 |
-
print(
|
51 |
-
"For more details about Webhook secrets, please refer to https://huggingface.co/docs/hub/webhooks#webhook-secret."
|
52 |
-
)
|
53 |
-
else:
|
54 |
-
print("\nWebhook secret is correctly defined.")
|
55 |
-
app.middleware("http")(self._webhook_secret_middleware)
|
56 |
-
|
57 |
-
def add_webhook(self, path: str):
|
58 |
-
"""Decorator to add a webhook to the server app."""
|
59 |
-
self.webhook_paths.add(path)
|
60 |
-
return self.fastapi_app.post(path)
|
61 |
-
|
62 |
-
def ready(self) -> None:
|
63 |
-
"""Set the app as "ready" and block main thread to keep it running."""
|
64 |
-
url = (
|
65 |
-
self.gradio_app.share_url
|
66 |
-
if self.gradio_app.share_url is not None
|
67 |
-
else self.gradio_app.local_url
|
68 |
-
).strip("/")
|
69 |
-
print("\nWebhooks are correctly setup and ready to use:")
|
70 |
-
print("\n".join(f" - POST {url}{webhook}" for webhook in self.webhook_paths))
|
71 |
-
print("Go to https://huggingface.co/settings/webhooks to setup your webhooks.")
|
72 |
-
self.gradio_app.block_thread()
|
73 |
-
|
74 |
-
async def _webhook_secret_middleware(self, request: Request, call_next) -> None:
|
75 |
-
"""Middleware to check "X-Webhook-Secret" header on every webhook request."""
|
76 |
-
if request.url.path in self.webhook_paths:
|
77 |
-
if self._webhook_secret is not None:
|
78 |
-
request_secret = request.headers.get("x-webhook-secret")
|
79 |
-
if request_secret is None:
|
80 |
-
return JSONResponse(
|
81 |
-
{"error": "x-webhook-secret header not set."}, status_code=401
|
82 |
-
)
|
83 |
-
if request_secret != self._webhook_secret:
|
84 |
-
return JSONResponse(
|
85 |
-
{"error": "Invalid webhook secret."}, status_code=403
|
86 |
-
)
|
87 |
-
return await call_next(request)
|
88 |
-
|
89 |
-
|
90 |
-
class WebhookPayloadEvent(BaseModel):
|
91 |
-
action: Literal["create", "update", "delete"]
|
92 |
-
scope: str
|
93 |
-
|
94 |
-
|
95 |
-
class WebhookPayloadRepo(BaseModel):
|
96 |
-
type: Literal["dataset", "model", "space"]
|
97 |
-
name: str
|
98 |
-
private: bool
|
99 |
-
|
100 |
-
|
101 |
-
class WebhookPayloadDiscussion(BaseModel):
|
102 |
-
num: int
|
103 |
-
isPullRequest: bool
|
104 |
-
status: Literal["open", "closed", "merged"]
|
105 |
-
|
106 |
-
|
107 |
-
class WebhookPayload(BaseModel):
|
108 |
-
event: WebhookPayloadEvent
|
109 |
-
repo: WebhookPayloadRepo
|
110 |
-
discussion: Optional[WebhookPayloadDiscussion]
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
requirements.txt
CHANGED
@@ -1,2 +1,2 @@
|
|
1 |
-
|
2 |
-
huggingface_hub
|
|
|
1 |
+
gradio
|
2 |
+
git+https://github.com/huggingface/huggingface_hub@feat-webhook-app#egg=huggingface_hub
|
simple.py
DELETED
@@ -1,12 +0,0 @@
|
|
1 |
-
from gradio_webhooks import GradioWebhookApp, WebhookPayload
|
2 |
-
|
3 |
-
app = GradioWebhookApp(webhook_secret="my_dummy_secret")
|
4 |
-
|
5 |
-
|
6 |
-
@app.add_webhook("/my_webhook")
|
7 |
-
async def hello(payload: WebhookPayload):
|
8 |
-
print(f"Received webhook for repo {payload.repo.name}")
|
9 |
-
return {"processed": True}
|
10 |
-
|
11 |
-
|
12 |
-
app.ready()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
ui.py
CHANGED
@@ -21,7 +21,7 @@ You are a few clicks away from having the CI Bot configured on your Spaces. No c
|
|
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/
|
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)
|
|
|
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/webhooks/trigger_ci_on_pr>.
|
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)
|