Wauplin HF staff commited on
Commit
7403ab9
1 Parent(s): 9ab0827
Files changed (4) hide show
  1. README.md +2 -2
  2. app.py +30 -4
  3. open_pr.py +127 -0
  4. setup.py +1 -1
README.md CHANGED
@@ -37,8 +37,8 @@ space_ci:
37
 
38
  # Listen to Pull Requests and start ephemeral Spaces on new PRs! 🚀
39
 
40
- **Gradio Space CI** is a plugin (and package) to create ephemeral Spaces for each PR opened on your Space repo.
41
- The goal is to foster community contributions by making the review process as lean as possible.
42
 
43
  #### ⚠️ Disclaimer: **Gradio Space CI** works only on public Spaces.
44
 
 
37
 
38
  # Listen to Pull Requests and start ephemeral Spaces on new PRs! 🚀
39
 
40
+ **Gradio Space CI** is a tool to create ephemeral Spaces for each PR opened on your Space repo.
41
+ The goal is to improve developer experience by making the review process as lean as possible.
42
 
43
  #### ⚠️ Disclaimer: **Gradio Space CI** works only on public Spaces.
44
 
app.py CHANGED
@@ -1,12 +1,38 @@
1
  #!/usr/bin/env python
2
- from pathlib import Path
3
 
4
  import gradio as gr
5
  from gradio_space_ci import enable_space_ci
6
 
 
 
7
  enable_space_ci()
8
 
9
- with gr.Blocks() as demo:
10
- gr.Markdown(Path("README.md").read_text().split("---")[-1])
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
 
12
- demo.launch()
 
 
 
 
 
 
 
 
 
 
1
  #!/usr/bin/env python
 
2
 
3
  import gradio as gr
4
  from gradio_space_ci import enable_space_ci
5
 
6
+ from open_pr import open_pr
7
+
8
  enable_space_ci()
9
 
10
+ DESCRIPTION = """
11
+ ## Gradio Space CI is a tool to create ephemeral Spaces for each PR opened on your Space repo.
12
+
13
+ The goal is to improve developer experience by making the review process as lean as possible.
14
+ The app below let you open a PR to enable Space CI on a Space.
15
+
16
+ The steps are the following:
17
+ 1. Paste a read-access token from hf.co/settings/tokens. Read access is enough given that we will open a PR against the source repo.
18
+ 2. Input a Space id from the Hub
19
+ 3. Click "Submit"
20
+ 4. That's it! You'll get feedback if it works or not, and if it worked, you'll get the URL of the opened PR 🔥
21
+
22
+ #### ⚠️ Disclaimer: **Gradio Space CI** works only on public Spaces.
23
+
24
+ For more details about **Gradio Space CI**, checkout [this page]](https://huggingface.co/spaces/Wauplin/gradio-space-ci/blob/main/README.md).
25
+
26
+ If you find any issues, please report here: https://huggingface.co/spaces/Wauplin/gradio-space-ci/discussions
27
+ """
28
 
29
+ gr.Interface(
30
+ fn=open_pr,
31
+ inputs=["text", "text"],
32
+ outputs="markdown",
33
+ title="Listen to Pull Requests and start ephemeral Spaces on new PRs! 🚀",
34
+ description=DESCRIPTION,
35
+ article="Provide a space ID and a token and click 'Submit'. A PR will be open to Space CI on the provided Space. You don't have to be the Space owner to open the PR.",
36
+ allow_flagging=False,
37
+ allow_duplication=False,
38
+ ).launch()
open_pr.py ADDED
@@ -0,0 +1,127 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import re
2
+
3
+ import gradio as gr
4
+ from huggingface_hub import CommitOperationAdd, HfApi, RepoUrl, SpaceCard
5
+
6
+ IMPORTS_REGEX = re.compile(r"^(from|import) .*$", re.MULTILINE)
7
+
8
+ PR_DESCRIPTION = """
9
+ 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.
10
+
11
+ ### ⚙️ How it works:
12
+
13
+ - Listens to pull requests events:
14
+ - If PR is opened => starts an ephemeral Space
15
+ - If PR is updated => updates the Space
16
+ - If PR is closed => deleted the Space
17
+ - Checks PR author:
18
+ - If trusted author => ephemeral Space is configured with variables, secrets and hardware.
19
+ - If not a trusted author => ephemeral Space is started without configuration.
20
+ - Space owners are trusted by default. Additional "trusted authors" can be configuration manually.
21
+
22
+ ### ⚠️ Before merging:
23
+
24
+ 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.
25
+ 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).
26
+
27
+ ---
28
+ This is an automated PR created with https://huggingface.co/spaces/Wauplin/gradio-space-ci.
29
+ For more details about Space CI, checkout [this page]](https://huggingface.co/spaces/Wauplin/gradio-space-ci/blob/main/README.md).
30
+ If you find any issues, please report here: https://huggingface.co/spaces/Wauplin/gradio-space-ci/discussions
31
+
32
+ Feel free to ignore this PR.
33
+ """
34
+
35
+ SUCCESS_MESSAGE = """
36
+ ### Success 🔥
37
+
38
+ Yay! A PR has been open to enable Space CI on {space_id}. Check it out here: [{pr_url}]({pr_url}).
39
+
40
+ You can contact the Space owner to let them know about this PR.
41
+ """
42
+
43
+
44
+ def open_pr(space_id_or_url: str, token: str) -> str:
45
+ api = HfApi(token=token)
46
+
47
+ space_id = (
48
+ RepoUrl(space_id_or_url).repo_id if "https://huggingface.co/spaces/" in space_id_or_url else space_id_or_url
49
+ )
50
+
51
+ # 0. Check token + repo existence
52
+ try:
53
+ user = api.whoami()
54
+ if user["type"] != "user":
55
+ raise gr.Error(
56
+ "You must use a user token, not an organization token. Go to https://huggingface.co/settings/token to create a new token."
57
+ )
58
+ except Exception as e:
59
+ raise gr.Error("Invalid token: {e}") from e
60
+
61
+ if not api.repo_exists(space_id, repo_type="space"):
62
+ raise gr.Error(f"Space does not exist: 'https://huggingface.co/spaces/{space_id}'.")
63
+
64
+ # 1. Add to requirements.txt
65
+ if api.file_exists(repo_id=space_id, repo_type="space", filename="requirements.txt"):
66
+ requirements_file = api.hf_hub_download(repo_id=space_id, repo_type="space", filename="requirements.txt")
67
+ with open(requirements_file) as f:
68
+ requirements = f.read()
69
+ else:
70
+ requirements = ""
71
+ if "gradio-space-ci" not in requirements:
72
+ requirements += "\ngradio-space-ci @ git+https://huggingface.co/spaces/Wauplin/gradio-space-ci@0.2.1\n"
73
+
74
+ # 2. Configure CI in README.md
75
+ card = SpaceCard.load(api.hf_hub_download(repo_id=space_id, repo_type="space", filename="README.md"))
76
+ card.data["space_ci"] = {
77
+ "trusted_authors": [],
78
+ "secrets": [],
79
+ "hardware": "cpu-basic",
80
+ "storage": None,
81
+ }
82
+ if card.data.sdk != "gradio":
83
+ raise gr.Error(f"Space must be a Gradio Space, not '{card.data.sdk}'.")
84
+ app_file = card.data.app_file
85
+ if app_file is None:
86
+ raise gr.Error("Space must have an app_file defined their README.")
87
+ if not api.file_exists(repo_id=space_id, repo_type="space", filename=app_file):
88
+ raise gr.Error(f"Could not find app file '{app_file}' in Space repo.")
89
+
90
+
91
+ # 3. Enable CI in app.py
92
+ with open(api.hf_hub_download(repo_id=space_id, repo_type="space", filename=app_file)) as f:
93
+ app = f.read()
94
+ if "enable_space_ci()" in app:
95
+ raise gr.Error("Space CI is already enabled.")
96
+
97
+ all_imports = list(IMPORTS_REGEX.finditer(app))
98
+ if len(all_imports) == 0:
99
+ raise gr.Error("Could not find any imports in app.py.")
100
+ last_import = all_imports[-1]
101
+
102
+ app = (
103
+ app[: last_import.end()]
104
+ + "\n\n"
105
+ + "from gradio_space_ci import enable_space_ci"
106
+ + "\n\n"
107
+ + "enable_space_ci()"
108
+ + "\n\n"
109
+ + app[last_import.end() :]
110
+ )
111
+
112
+ # 4. Push changes as a PR
113
+ commit = api.create_commit(
114
+ repo_id=space_id,
115
+ repo_type="space",
116
+ operations=[
117
+ CommitOperationAdd(path_in_repo="README.md", path_or_fileobj=str(card).encode()),
118
+ CommitOperationAdd(path_in_repo="requirements.txt", path_or_fileobj=requirements.encode()),
119
+ CommitOperationAdd(path_in_repo=app_file, path_or_fileobj=app.encode()),
120
+ ],
121
+ commit_message="Enable Space CI",
122
+ commit_description=PR_DESCRIPTION,
123
+ create_pr=True,
124
+ )
125
+ assert commit.pr_url is not None # since `create_pr=True`
126
+
127
+ return SUCCESS_MESSAGE.format(space_id=space_id, pr_url=commit.pr_url)
setup.py CHANGED
@@ -14,7 +14,7 @@ def get_version() -> str:
14
  install_requires = [
15
  "gradio",
16
  # TODO: update once released
17
- "huggingface_hub @ git+https://github.com/huggingface/huggingface_hub@7c74445903fe86f694ce6e42c386b7bebee94008"
18
  ]
19
 
20
  extras = {}
 
14
  install_requires = [
15
  "gradio",
16
  # TODO: update once released
17
+ "huggingface_hub @ git+https://github.com/huggingface/huggingface_hub@7c74445903fe86f694ce6e42c386b7bebee94008",
18
  ]
19
 
20
  extras = {}