BirkhoffLee commited on
Commit
c809ef4
·
unverified ·
1 Parent(s): 860be47

feat: 增加了自动部署 CI

Browse files
Files changed (5) hide show
  1. .cnb.yml +23 -5
  2. .dockerignore +5 -0
  3. README.md +13 -0
  4. basic_auth_users.txt +3 -0
  5. scripts/update_space_secret.py +58 -0
.cnb.yml CHANGED
@@ -9,7 +9,7 @@ $:
9
  imports:
10
  - https://cnb.cool/maikebuke/Tools/Huggingface/AccessToken/-/blob/main/key.yml
11
  env:
12
- HF_SPACE_URL: "https://huggingface.co/spaces/ServiceX/Sublink"
13
  services:
14
  - vscode
15
  - docker
@@ -24,16 +24,34 @@ main:
24
  imports:
25
  - https://cnb.cool/maikebuke/Tools/Huggingface/AccessToken/-/blob/main/key.yml
26
  env:
27
- HF_SPACE_URL: "https://huggingface.co/spaces/ServiceX/Sublink"
 
 
 
28
  stages:
29
- - name: Force Push To Huggingface Spaces
30
  script: |
 
 
 
 
 
 
 
 
 
 
 
 
 
31
  # 从 HF_SPACE_URL 提取 owner/repo 路径用于构造带认证的 git remote
32
  HF_REPO_PATH=$(echo "$HF_SPACE_URL" | sed 's|https://huggingface.co/spaces/||')
33
  HF_REMOTE="https://user:${HF_TOKEN_FULL}@huggingface.co/spaces/${HF_REPO_PATH}"
34
 
35
- # 删除 CI 文件,避免推送到目标仓库
36
- rm -f .cnb.yml
 
 
37
 
38
  git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
39
  git config user.name "github-actions[bot]"
 
9
  imports:
10
  - https://cnb.cool/maikebuke/Tools/Huggingface/AccessToken/-/blob/main/key.yml
11
  env:
12
+ HF_SPACE_URL: "https://huggingface.co/spaces/ServiceX/PDF"
13
  services:
14
  - vscode
15
  - docker
 
24
  imports:
25
  - https://cnb.cool/maikebuke/Tools/Huggingface/AccessToken/-/blob/main/key.yml
26
  env:
27
+ HF_SPACE_URL: "https://huggingface.co/spaces/ServiceX/PDF"
28
+ HF_SPACE_SECRET_KEY: "BASIC_AUTH_USERS"
29
+ BASIC_AUTH_FILE: "basic_auth_users.txt"
30
+ HF_EXCLUDE_FILES: ".cnb.yml basic_auth_users.txt scripts"
31
  stages:
32
+ - name: Update HF Space Secret
33
  script: |
34
+ set -euo pipefail
35
+
36
+ HF_TOKEN="${HF_TOKEN_FULL}" uvx --from huggingface_hub hf auth whoami >/dev/null
37
+ HF_TOKEN_FULL="${HF_TOKEN_FULL}" \
38
+ HF_SPACE_URL="${HF_SPACE_URL}" \
39
+ HF_SPACE_SECRET_KEY="${HF_SPACE_SECRET_KEY}" \
40
+ BASIC_AUTH_FILE="${BASIC_AUTH_FILE}" \
41
+ uvx --from huggingface_hub python scripts/update_space_secret.py
42
+
43
+ - name: Push Git To Huggingface Spaces
44
+ script: |
45
+ set -euo pipefail
46
+
47
  # 从 HF_SPACE_URL 提取 owner/repo 路径用于构造带认证的 git remote
48
  HF_REPO_PATH=$(echo "$HF_SPACE_URL" | sed 's|https://huggingface.co/spaces/||')
49
  HF_REMOTE="https://user:${HF_TOKEN_FULL}@huggingface.co/spaces/${HF_REPO_PATH}"
50
 
51
+ # 删除不应同步到 Spaces 文件(空格分隔)
52
+ for exclude in ${HF_EXCLUDE_FILES}; do
53
+ rm -rf "$exclude"
54
+ done
55
 
56
  git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
57
  git config user.name "github-actions[bot]"
.dockerignore ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
 
1
+ # 避免把仓库元数据和敏感文件打进镜像
2
+ .git
3
+ .cnb.yml
4
+ basic_auth_users.txt
5
+ scripts/
README.md CHANGED
@@ -32,6 +32,19 @@ bob:your_password_2
32
  - 空行和 `#` 开头行会被忽略
33
  - 容器启动时会把明文密码转换为 bcrypt 哈希,仓库不保存真实密码
34
 
 
 
 
 
 
 
 
 
 
 
 
 
 
35
  ### 健康检查
36
 
37
  `/healthz` 无需认证,返回 `200 ok`。
 
32
  - 空行和 `#` 开头行会被忽略
33
  - 容器启动时会把明文密码转换为 bcrypt 哈希,仓库不保存真实密码
34
 
35
+ ### CI 同步到 Spaces 的排除策略
36
+
37
+ - 本仓库可本地维护密码文件:`basic_auth_users.txt`
38
+ - CNB `push` 分两个阶段:
39
+ - 阶段 1:读取 `basic_auth_users.txt`,自动更新 Space Secret `BASIC_AUTH_USERS`
40
+ - 阶段 2:删除排除文件后,强制推送代码到 HuggingFace Spaces
41
+ - 推送前会删除以下文件:
42
+ - `.cnb.yml`
43
+ - `basic_auth_users.txt`
44
+ - `scripts/`
45
+ - 排除列表在 `.cnb.yml` 的 `HF_EXCLUDE_FILES` 中配置(空格分隔)
46
+ - 密钥更新脚本:`scripts/update_space_secret.py`
47
+
48
  ### 健康检查
49
 
50
  `/healthz` 无需认证,返回 `200 ok`。
basic_auth_users.txt ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ # 每行一个账号,格式:username:password
2
+ alice:change_me_please
3
+ bob:change_me_too
scripts/update_space_secret.py ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ #!/usr/bin/env python3
2
+ """Update Hugging Face Space secret from a local credential file."""
3
+
4
+ from __future__ import annotations
5
+
6
+ import os
7
+ from pathlib import Path
8
+ from urllib.parse import urlparse
9
+
10
+ from huggingface_hub import HfApi
11
+
12
+
13
+ def _require_env(name: str) -> str:
14
+ value = os.environ.get(name, "").strip()
15
+ if not value:
16
+ raise SystemExit(f"[ERROR] Missing required environment variable: {name}")
17
+ return value
18
+
19
+
20
+ def _parse_space_repo_id(space_url: str) -> str:
21
+ prefix = "https://huggingface.co/spaces/"
22
+ if space_url.startswith(prefix):
23
+ repo_id = space_url[len(prefix) :].strip("/")
24
+ else:
25
+ parsed = urlparse(space_url)
26
+ parts = [part for part in parsed.path.split("/") if part]
27
+ # 期望路径格式: /spaces/{owner}/{repo}
28
+ if len(parts) >= 3 and parts[0] == "spaces":
29
+ repo_id = f"{parts[1]}/{parts[2]}"
30
+ else:
31
+ raise SystemExit(f"[ERROR] Invalid HF_SPACE_URL: {space_url}")
32
+
33
+ if "/" not in repo_id:
34
+ raise SystemExit(f"[ERROR] Invalid Space repo id: {repo_id}")
35
+ return repo_id
36
+
37
+
38
+ def main() -> None:
39
+ token = _require_env("HF_TOKEN_FULL")
40
+ space_url = _require_env("HF_SPACE_URL")
41
+ secret_key = os.environ.get("HF_SPACE_SECRET_KEY", "BASIC_AUTH_USERS").strip()
42
+ auth_file = os.environ.get("BASIC_AUTH_FILE", "basic_auth_users.txt").strip()
43
+
44
+ auth_path = Path(auth_file)
45
+ if not auth_path.is_file():
46
+ raise SystemExit(f"[ERROR] Auth file not found: {auth_file}")
47
+
48
+ secret_value = auth_path.read_text(encoding="utf-8").strip()
49
+ if not secret_value:
50
+ raise SystemExit(f"[ERROR] Auth file is empty: {auth_file}")
51
+
52
+ repo_id = _parse_space_repo_id(space_url)
53
+ HfApi(token=token).add_space_secret(repo_id=repo_id, key=secret_key, value=secret_value)
54
+ print(f"[INFO] Updated Space secret '{secret_key}' for '{repo_id}'.")
55
+
56
+
57
+ if __name__ == "__main__":
58
+ main()