bb-sync 1.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bb_sync-1.9.0/.github/workflows/ci.yml +103 -0
- bb_sync-1.9.0/.github/workflows/release.yml +48 -0
- bb_sync-1.9.0/.gitignore +20 -0
- bb_sync-1.9.0/.pre-commit-config.yaml +7 -0
- bb_sync-1.9.0/AGENTS.md +130 -0
- bb_sync-1.9.0/CHANGELOG.md +327 -0
- bb_sync-1.9.0/CONTRIBUTING.md +64 -0
- bb_sync-1.9.0/LICENSE +21 -0
- bb_sync-1.9.0/PKG-INFO +265 -0
- bb_sync-1.9.0/README.md +214 -0
- bb_sync-1.9.0/config.yaml +30 -0
- bb_sync-1.9.0/docs/config.md +187 -0
- bb_sync-1.9.0/docs/scripting.md +127 -0
- bb_sync-1.9.0/pyproject.toml +94 -0
- bb_sync-1.9.0/scripts/debug_course.py +81 -0
- bb_sync-1.9.0/scripts/debug_courses.py +78 -0
- bb_sync-1.9.0/scripts/debug_login.py +79 -0
- bb_sync-1.9.0/src/bb_sync/__init__.py +23 -0
- bb_sync-1.9.0/src/bb_sync/__main__.py +8 -0
- bb_sync-1.9.0/src/bb_sync/blackboard/__init__.py +5 -0
- bb_sync-1.9.0/src/bb_sync/blackboard/downloader.py +348 -0
- bb_sync-1.9.0/src/bb_sync/blackboard/login.py +190 -0
- bb_sync-1.9.0/src/bb_sync/blackboard/models.py +143 -0
- bb_sync-1.9.0/src/bb_sync/blackboard/scraper.py +695 -0
- bb_sync-1.9.0/src/bb_sync/browser/__init__.py +5 -0
- bb_sync-1.9.0/src/bb_sync/browser/steel.py +511 -0
- bb_sync-1.9.0/src/bb_sync/cli.py +302 -0
- bb_sync-1.9.0/src/bb_sync/commands/__init__.py +5 -0
- bb_sync-1.9.0/src/bb_sync/commands/auth.py +80 -0
- bb_sync-1.9.0/src/bb_sync/commands/config.py +239 -0
- bb_sync-1.9.0/src/bb_sync/commands/course.py +45 -0
- bb_sync-1.9.0/src/bb_sync/commands/doctor.py +65 -0
- bb_sync-1.9.0/src/bb_sync/commands/due.py +66 -0
- bb_sync-1.9.0/src/bb_sync/commands/run.py +74 -0
- bb_sync-1.9.0/src/bb_sync/context.py +69 -0
- bb_sync-1.9.0/src/bb_sync/core/__init__.py +5 -0
- bb_sync-1.9.0/src/bb_sync/core/config.py +205 -0
- bb_sync-1.9.0/src/bb_sync/core/config_store.py +190 -0
- bb_sync-1.9.0/src/bb_sync/core/doctor.py +230 -0
- bb_sync-1.9.0/src/bb_sync/core/due.py +192 -0
- bb_sync-1.9.0/src/bb_sync/core/errors.py +107 -0
- bb_sync-1.9.0/src/bb_sync/core/output.py +151 -0
- bb_sync-1.9.0/src/bb_sync/core/service.py +446 -0
- bb_sync-1.9.0/src/bb_sync/core/update.py +286 -0
- bb_sync-1.9.0/src/bb_sync/creds.py +91 -0
- bb_sync-1.9.0/src/bb_sync/paths.py +26 -0
- bb_sync-1.9.0/tests/conftest.py +182 -0
- bb_sync-1.9.0/tests/test_cli_e2e.py +483 -0
- bb_sync-1.9.0/tests/test_units.py +2125 -0
- bb_sync-1.9.0/tests/test_update_e2e.py +86 -0
- bb_sync-1.9.0/uv.lock +780 -0
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
pull_request:
|
|
7
|
+
|
|
8
|
+
# 同分支连推时只跑最新一次,跳过被取代的旧 run
|
|
9
|
+
concurrency:
|
|
10
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
11
|
+
cancel-in-progress: true
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
quality-matrix:
|
|
15
|
+
name: quality (${{ matrix.os }})
|
|
16
|
+
strategy:
|
|
17
|
+
fail-fast: false
|
|
18
|
+
matrix:
|
|
19
|
+
os: [ubuntu-latest, macos-latest, windows-latest]
|
|
20
|
+
runs-on: ${{ matrix.os }}
|
|
21
|
+
steps:
|
|
22
|
+
- uses: actions/checkout@v4
|
|
23
|
+
|
|
24
|
+
- name: Install uv
|
|
25
|
+
uses: astral-sh/setup-uv@v5
|
|
26
|
+
with:
|
|
27
|
+
enable-cache: true
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: uv sync
|
|
31
|
+
|
|
32
|
+
- name: Ruff lint
|
|
33
|
+
run: uv run ruff check .
|
|
34
|
+
|
|
35
|
+
- name: Ruff format check
|
|
36
|
+
run: uv run ruff format --check .
|
|
37
|
+
|
|
38
|
+
- name: Pyright type check
|
|
39
|
+
run: uv run pyright
|
|
40
|
+
|
|
41
|
+
- name: Pytest (unit + CLI e2e)
|
|
42
|
+
# 全部离线:不登录、不下载、不起浏览器。
|
|
43
|
+
# 覆盖 CLI 命令行契约、退出码语义、stdout/stderr 分流与配置读写,
|
|
44
|
+
# 等价于此前手工执行的全量回归。
|
|
45
|
+
run: uv run pytest -q
|
|
46
|
+
|
|
47
|
+
install-smoke:
|
|
48
|
+
name: install smoke (clean container)
|
|
49
|
+
# 模拟裸机:干净容器里按 README 前置条件装好依赖,再从 GitHub 安装 bb-sync 并验证
|
|
50
|
+
runs-on: ubuntu-latest
|
|
51
|
+
container: python:3.12-slim
|
|
52
|
+
env:
|
|
53
|
+
PYTHONUTF8: "1"
|
|
54
|
+
steps:
|
|
55
|
+
- uses: actions/checkout@v4
|
|
56
|
+
if: github.event_name == 'pull_request'
|
|
57
|
+
|
|
58
|
+
- name: Install prerequisites (git + uv)
|
|
59
|
+
run: |
|
|
60
|
+
apt-get update -qq && apt-get install -y -qq git ca-certificates >/dev/null
|
|
61
|
+
pip install --quiet uv
|
|
62
|
+
|
|
63
|
+
- name: Install bb-sync
|
|
64
|
+
run: |
|
|
65
|
+
if [ "${{ github.event_name }}" = "pull_request" ]; then
|
|
66
|
+
uv tool install .
|
|
67
|
+
else
|
|
68
|
+
uv tool install git+https://github.com/${{ github.repository }}
|
|
69
|
+
fi
|
|
70
|
+
|
|
71
|
+
- name: Put uv tool bin on PATH
|
|
72
|
+
run: echo "$HOME/.local/bin" >> "$GITHUB_PATH"
|
|
73
|
+
|
|
74
|
+
- name: Smoke test
|
|
75
|
+
run: |
|
|
76
|
+
bb-sync --version
|
|
77
|
+
# 注意:doctor 的诊断输出走 stderr(stdout 只留给 --json 的结构化结果),
|
|
78
|
+
# 因此必须用 2>&1 才能把体检结果落进文件供 grep 断言。
|
|
79
|
+
# 容器里没有 Node/浏览器,doctor 会报缺项(预期,退出码非 0),只断言基础项
|
|
80
|
+
bb-sync doctor > doctor.txt 2>&1 || true
|
|
81
|
+
grep -q "✓.*Python" doctor.txt
|
|
82
|
+
grep -q "✓.*git" doctor.txt
|
|
83
|
+
grep -q "✓.*网络" doctor.txt
|
|
84
|
+
# CLI 结构断言:无参数出帮助且退出码 0
|
|
85
|
+
bb-sync >/dev/null
|
|
86
|
+
test $? -eq 0
|
|
87
|
+
# 未知命令退出码 2(用法错误)。
|
|
88
|
+
# 注意 GitHub Actions 的 run 默认 set -e,非零退出会立刻中断脚本,
|
|
89
|
+
# 因此必须用 || true(或 if !)兜住,才能拿到 $? 做断言。
|
|
90
|
+
rc=0
|
|
91
|
+
bb-sync definitely-not-a-command >/dev/null 2>&1 || rc=$?
|
|
92
|
+
test "$rc" -eq 2
|
|
93
|
+
# --json 的 JSON 必须落在 stdout 且可被解析(诊断走 stderr 不污染)
|
|
94
|
+
bb-sync --json doctor 2>/dev/null | python -c "import json,sys; json.load(sys.stdin)"
|
|
95
|
+
|
|
96
|
+
# 分支保护要求状态检查名为 `quality`;矩阵任务改名后由这个聚合门禁继续提供。
|
|
97
|
+
quality:
|
|
98
|
+
name: quality
|
|
99
|
+
needs: quality-matrix
|
|
100
|
+
runs-on: ubuntu-latest
|
|
101
|
+
steps:
|
|
102
|
+
- name: All platform checks passed
|
|
103
|
+
run: echo "Ubuntu, macOS and Windows quality checks passed"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
tags: ["v*"]
|
|
6
|
+
|
|
7
|
+
# contents: write 用于建 Release;id-token: write 供 PyPI 信任发布(OIDC)换取短期凭据,
|
|
8
|
+
# 不需要在仓库里存任何 PyPI token。
|
|
9
|
+
permissions:
|
|
10
|
+
contents: write
|
|
11
|
+
id-token: write
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
release:
|
|
15
|
+
runs-on: ubuntu-latest
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: actions/setup-python@v5
|
|
20
|
+
with:
|
|
21
|
+
python-version: "3.12"
|
|
22
|
+
|
|
23
|
+
- name: Build distributions
|
|
24
|
+
run: |
|
|
25
|
+
python -m pip install --upgrade pip build
|
|
26
|
+
python -m build
|
|
27
|
+
|
|
28
|
+
- name: Verify artifact version matches tag
|
|
29
|
+
# 防止「tag 打了 v1.0.0,包里却是别的版本号」这种低级但致命的发布事故
|
|
30
|
+
run: |
|
|
31
|
+
TAG="${GITHUB_REF_NAME#v}"
|
|
32
|
+
ls dist/
|
|
33
|
+
test -f "dist/bb_sync-${TAG}-py3-none-any.whl" || {
|
|
34
|
+
echo "::error::构建产物版本与 tag 不一致:期望 bb_sync-${TAG}-py3-none-any.whl"
|
|
35
|
+
exit 1
|
|
36
|
+
}
|
|
37
|
+
echo "版本校验通过:${TAG}"
|
|
38
|
+
|
|
39
|
+
- name: Create GitHub Release
|
|
40
|
+
uses: softprops/action-gh-release@v2
|
|
41
|
+
with:
|
|
42
|
+
generate_release_notes: true
|
|
43
|
+
files: dist/*
|
|
44
|
+
|
|
45
|
+
# 发布到 PyPI:走 Trusted Publishing,凭 OIDC 换临时 token,无需任何长期密钥。
|
|
46
|
+
# 前置条件:PyPI 上已为该仓库配置 pending publisher(见 README / 发布说明)。
|
|
47
|
+
- name: Publish to PyPI
|
|
48
|
+
uses: pypa/gh-action-pypi-publish@release/v1
|
bb_sync-1.9.0/.gitignore
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# 登录态浏览器 profile(绝不入库)
|
|
2
|
+
.browser-profile/
|
|
3
|
+
|
|
4
|
+
# 本地运行时
|
|
5
|
+
.venv/
|
|
6
|
+
__pycache__/
|
|
7
|
+
*.pyc
|
|
8
|
+
.steel/
|
|
9
|
+
steel*.log
|
|
10
|
+
*.egg-info/
|
|
11
|
+
dist/
|
|
12
|
+
|
|
13
|
+
# 运行时生成的调试产物(debug_*.py 调试脚本保留入库)
|
|
14
|
+
debug_*.png
|
|
15
|
+
debug_*.html
|
|
16
|
+
debug_*.txt
|
|
17
|
+
|
|
18
|
+
# 个人工作区与课程资料(课程资料属版权内容,禁止公开)
|
|
19
|
+
.workbuddy/
|
|
20
|
+
courses/
|
bb_sync-1.9.0/AGENTS.md
ADDED
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
本文件给 AI 编码代理提供在 bb-sync 仓库中工作的必要上下文。
|
|
4
|
+
人类文档见 [README.md](README.md)(安装使用)、[CONTRIBUTING.md](CONTRIBUTING.md)(开发流程)、
|
|
5
|
+
[docs/](docs/)(配置与脚本化)。
|
|
6
|
+
|
|
7
|
+
## 项目速览
|
|
8
|
+
|
|
9
|
+
- **是什么**:Blackboard 课程资源自动同步 CLI。登录香港中文大学(深圳)的 `bb.cuhk.edu.cn`
|
|
10
|
+
(ADFS SSO),把课件 / 作业 / 指导增量下载到课程目录,公告保存为 Markdown。
|
|
11
|
+
- **仅适配** `bb.cuhk.edu.cn` 及其 ADFS 登录流程;不要为其他站点引入通用化假设。
|
|
12
|
+
- **目标平台**:Windows 10/11 与 macOS(Intel / Apple Silicon);文档示例需覆盖
|
|
13
|
+
PowerShell 与 zsh / bash。
|
|
14
|
+
- **技术栈**:Python ≥3.11;Typer + Click(CLI)、pydantic v2(配置)、PyYAML、rich(输出)、
|
|
15
|
+
keyring(凭据)、Playwright(浏览器自动化)。
|
|
16
|
+
- **浏览器后端**:Steel——本地 Node ≥22 服务,通过 CDP 接入,Chrome profile 持久化登录态。
|
|
17
|
+
- **打包**:hatchling,`src/` 布局,入口 `bb-sync = bb_sync.cli:main`。
|
|
18
|
+
- **语言**:代码注释、docstring、提交信息、用户文档一律中文。安装与路径示例同时覆盖
|
|
19
|
+
Windows PowerShell 和 macOS zsh / bash。
|
|
20
|
+
|
|
21
|
+
## 目录导航
|
|
22
|
+
|
|
23
|
+
| 路径 | 职责 |
|
|
24
|
+
| --- | --- |
|
|
25
|
+
| `src/bb_sync/cli.py` | 入口:Typer/Click 组装、全局选项、统一异常兜底与退出码 |
|
|
26
|
+
| `src/bb_sync/context.py` | 全局 Context(`--json/--quiet/--verbose/--config`),惰性导入 |
|
|
27
|
+
| `src/bb_sync/paths.py` | `BB_SYNC_HOME`(默认 `~/.bb-sync`)与配置文件查找 |
|
|
28
|
+
| `src/bb_sync/creds.py` | keyring 凭据读写 |
|
|
29
|
+
| `src/bb_sync/commands/` | 子命令:run / doctor / config / auth / course |
|
|
30
|
+
| `src/bb_sync/core/` | config(分层加载)、config_store(行级 YAML 编辑)、service(同步编排)、doctor、output(Console)、errors(退出码) |
|
|
31
|
+
| `src/bb_sync/blackboard/` | login(ADFS SSO)、scraper(列表 / 内容抓取)、downloader、models |
|
|
32
|
+
| `src/bb_sync/browser/steel.py` | Steel 后端定位 / 安装 / 启动、CDP 会话、持久 profile |
|
|
33
|
+
| `tests/` | 全部离线:`test_units.py`(纯逻辑)+ `test_cli_e2e.py`(进程内 CLI 契约) |
|
|
34
|
+
| `scripts/debug_*.py` | 手工调试脚本,会真实登录 / 访问站点;不属于测试,不要在 CI 或非必要时运行 |
|
|
35
|
+
|
|
36
|
+
## 环境与常用命令
|
|
37
|
+
|
|
38
|
+
```shell
|
|
39
|
+
uv sync # 安装依赖(含 dev 组)
|
|
40
|
+
uv run bb-sync --help # 从源码运行 CLI
|
|
41
|
+
uv run pytest # 单元 + CLI 端到端(默认全离线)
|
|
42
|
+
uv run pytest tests/test_units.py -k <pattern> # 跑子集
|
|
43
|
+
uv run ruff check . # 静态检查
|
|
44
|
+
uv run ruff format . # 格式化(检查用 --check)
|
|
45
|
+
uv run pyright # 类型检查
|
|
46
|
+
uv run bb-sync doctor # 环境体检(触网;诊断走 stderr)
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
以上命令在 Windows PowerShell 与 macOS zsh / bash 中相同。macOS 前置依赖可用
|
|
50
|
+
`brew install git node uv` 安装。
|
|
51
|
+
|
|
52
|
+
只有真实运行 `run` / `course list` / `doctor`(未加 `--skip-network`)才需要 Node ≥22、
|
|
53
|
+
Chrome 或 Edge 和真实凭据;测试与质量检查完全离线。
|
|
54
|
+
|
|
55
|
+
### 提交前质量门禁(改动必须全绿)
|
|
56
|
+
|
|
57
|
+
```shell
|
|
58
|
+
uv run pytest
|
|
59
|
+
uv run ruff check .
|
|
60
|
+
uv run ruff format --check .
|
|
61
|
+
uv run pyright
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
涉及 CLI 契约、配置或输出通道的改动必须跑完整四件套;纯文档改动至少自查命令示例。
|
|
65
|
+
|
|
66
|
+
## 必须遵守的架构约定
|
|
67
|
+
|
|
68
|
+
### 1. 输出通道:stdout 只放结果,stderr 只放诊断
|
|
69
|
+
|
|
70
|
+
- 所有输出走 `core.output.Console`,**禁止直接 `print`**。
|
|
71
|
+
- `--json` 时 stdout 有且仅有一个 JSON 文档;出错时 stdout 保持为空,错误走 stderr。
|
|
72
|
+
- 新增命令或字段时,同步更新 `docs/scripting.md` 的 JSON 结构表与对应测试。
|
|
73
|
+
|
|
74
|
+
### 2. 退出码语义化
|
|
75
|
+
|
|
76
|
+
可预期错误一律抛 `BbSyncError` 子类(`core/errors.py`),由自带 `exit_code` 决定进程退出码:
|
|
77
|
+
0 成功、1 未分类、2 用法错误、3 登录 / 凭据、4 配置、5 网络、6 目标不存在、7 环境依赖、8 中断。
|
|
78
|
+
不要用裸 `sys.exit(1)` 或临时整数代替错误类型。
|
|
79
|
+
|
|
80
|
+
### 3. 冷启动:入口与 Context 不做重量级顶层导入
|
|
81
|
+
|
|
82
|
+
`cli.py` / `context.py` / `commands/__init__.py` 顶层不得导入 playwright、pydantic、rich 等,
|
|
83
|
+
命令模块按需延迟导入(`LazyGroup`),保证 `--version` / `--help` 快速返回。
|
|
84
|
+
`tests/test_cli_e2e.py` 有对应回归防线,不要绕过。
|
|
85
|
+
|
|
86
|
+
### 4. 配置:四层优先级 + 注释保留
|
|
87
|
+
|
|
88
|
+
CLI 参数 > `BB_SYNC_<KEY>` 环境变量 > config.yaml > 内置默认。
|
|
89
|
+
配置文件查找:CWD 优先,其次 `BB_SYNC_HOME/config.yaml`。
|
|
90
|
+
`config set/unset` 通过 `core/config_store.py` 做**行级编辑**,必须保留注释与未知键;
|
|
91
|
+
不要改成整份 YAML 重写。路径常量在 import 时快照,测试靠 monkeypatch 覆盖。
|
|
92
|
+
|
|
93
|
+
### 5. Steel 后端锚定快照
|
|
94
|
+
|
|
95
|
+
`browser/steel.py` 的 `STEEL_REF` 固定到验证过的 commit,不追随上游 `main`;
|
|
96
|
+
升级方式 = 改 `STEEL_REF` 并在 `CHANGELOG.md` 记录。
|
|
97
|
+
Steel 安装目录只能是 `BB_SYNC_HOME/.steel`,任何情况下不读写用户家目录的 `~/.steel`。
|
|
98
|
+
|
|
99
|
+
## 测试要求
|
|
100
|
+
|
|
101
|
+
- 默认测试套件必须离线:不登录、不下载、不起浏览器、不碰真实钥匙串。
|
|
102
|
+
`tests/conftest.py` 自动隔离 `BB_SYNC_HOME`、CWD、keyring 与 Steel 路径——
|
|
103
|
+
新测试直接依赖既有 fixture(`cli`、`config_file` 等),不要连接真实环境。
|
|
104
|
+
- 新行为要带测试:纯逻辑进 `tests/test_units.py`,CLI 契约 / 退出码 / 输出分流进 `tests/test_cli_e2e.py`。
|
|
105
|
+
- 真实站点逻辑(登录、抓取、下载)无法离线覆盖时,在提交信息或 PR 里写清可重复的手工验证步骤。
|
|
106
|
+
|
|
107
|
+
## 代码风格
|
|
108
|
+
|
|
109
|
+
- ruff(line-length 100、py311、isort 的 first-party 为 `bb_sync`)+ ruff format;pyright standard 零报错。
|
|
110
|
+
- 注释 / docstring 用中文解释职责与「为什么」;模块 docstring 说明关键约束。
|
|
111
|
+
- 全面类型标注,模块头用 `from __future__ import annotations`;面向用户的错误信息要带可操作 hint。
|
|
112
|
+
|
|
113
|
+
## 提交与发布
|
|
114
|
+
|
|
115
|
+
- 提交信息中文,格式 `feat|fix|docs|refactor|test|chore(范围): 摘要`;一个提交只做一件事。
|
|
116
|
+
- 只暂存本次相关文件;绝不提交密钥、`.env`、浏览器 profile、课程文件、构建产物(见 `.gitignore`)。
|
|
117
|
+
- 版本号在 `pyproject.toml`;打 `v*` tag 触发 `.github/workflows/release.yml`,
|
|
118
|
+
发布会校验 wheel 文件名与 tag 一致,并同步更新 `CHANGELOG.md`。
|
|
119
|
+
- CI(`.github/workflows/ci.yml`):Ruff lint / format、Pyright、pytest、干净容器安装冒烟。
|
|
120
|
+
|
|
121
|
+
## 常见坑
|
|
122
|
+
|
|
123
|
+
- 冷启动回归用例会先清掉 `bb_sync.commands.*` 再断言 `--help` 不导入它们;
|
|
124
|
+
新增 help 逻辑时不要触发真实导入。
|
|
125
|
+
- `bb-sync doctor` 的诊断输出走 stderr,stdout 只留给 `--json`;断言输出时先确认通道。
|
|
126
|
+
- GitHub Actions 的 run 默认 `set -e`,断言非零退出码需用 `|| true` 兜住(见 `ci.yml` 注释)。
|
|
127
|
+
- Windows 与 macOS 是主要目标平台,CI 同时跑 Ubuntu、macOS 与 Windows;路径、后台进程和
|
|
128
|
+
浏览器探测相关改动两个平台都要考虑。
|
|
129
|
+
- 首次准备 Steel 需从 GitHub / npm 拉依赖,国内网络慢时可临时用代理或镜像,不要写永久全局配置。
|
|
130
|
+
- 下载目录默认 `~/courses`,课程资料有版权;禁止提交或外传 `courses/`、`.workbuddy/` 内容。
|
|
@@ -0,0 +1,327 @@
|
|
|
1
|
+
# 更新日志
|
|
2
|
+
|
|
3
|
+
本项目遵循 [语义化版本](https://semver.org/lang/zh-CN/)。
|
|
4
|
+
|
|
5
|
+
## [1.9.0] — 2026-10-14
|
|
6
|
+
|
|
7
|
+
### 变更
|
|
8
|
+
|
|
9
|
+
- **仓库更名为 `cuhk-shenzhen-blackboard-sync`**(原 `bb-sync`),让校内同学更容易搜到。
|
|
10
|
+
GitHub 会自动重定向旧地址,已安装的用户不受影响;但 `bb-sync` 提示里的
|
|
11
|
+
更新 / 反馈链接、`pyproject.toml` 里的项目地址都已指向新仓库。
|
|
12
|
+
- **发布到 PyPI**:安装方式简化为 `uv tool install bb-sync`,不必再记 GitHub 地址。
|
|
13
|
+
发布走 Trusted Publishing,仓库里不保存任何 PyPI 密钥。
|
|
14
|
+
|
|
15
|
+
### 文档
|
|
16
|
+
|
|
17
|
+
- README 重写首页:补齐校名的各种写法(港中深 / 香港中文大学(深圳)/ CUHK-Shenzhen /
|
|
18
|
+
CUHKSZ),新增徽章、`due.md` 与下载目录示例、文档导航,并补全了此前遗漏的
|
|
19
|
+
`auth` / `config` 子命令。
|
|
20
|
+
- 免责声明补充说明:命令结束后会请求一次 GitHub Releases API 检查更新,
|
|
21
|
+
只发送 `bb-sync/<版本号>` 作为 User-Agent,可用 `BB_SYNC_NO_UPDATE_CHECK=1` 关闭。
|
|
22
|
+
|
|
23
|
+
## [1.8.1] — 2026-10-14
|
|
24
|
+
|
|
25
|
+
### 修复
|
|
26
|
+
|
|
27
|
+
- 公告里的测验 / 考试考完之后不再占待办位:`due.md` 新增「已过期事件」分组排在最后,
|
|
28
|
+
只供回看,既不挤进「已逾期」也不计进汇总行的「测验 N 项 / 考试 N 项」。此前公告类
|
|
29
|
+
待办只与「公告发布时间」比较,日期一过仍按待办列出。
|
|
30
|
+
- 公告事件过期超过 7 天后不再收录(`_PAST_EVENT_RETENTION_DAYS`):公告页会列出整
|
|
31
|
+
学期的公告,没有保留期的话考完的测验会一直堆在 `due.md` 里。
|
|
32
|
+
- 终端待办明细改为「日期(状态)| 课程 | 标题」,并在明细前打印「待办明细」分区标题:
|
|
33
|
+
已逾期的 To Do 标「逾期 N 天」,考完的测验 / 考试标「已过 N 天」。此前一屏只有日期,
|
|
34
|
+
看不出哪几条已经过期。
|
|
35
|
+
|
|
36
|
+
### 测试
|
|
37
|
+
|
|
38
|
+
- 新增公告事件保留期与「已过期事件」分组的用例;公告解析测试显式传入 `today`,
|
|
39
|
+
不再依赖运行当天的真实日期。
|
|
40
|
+
|
|
41
|
+
## [1.8.0] — 2026-10-13
|
|
42
|
+
|
|
43
|
+
### 新增
|
|
44
|
+
|
|
45
|
+
- `due.md` 除了课堂测验,也会从公告里整理带日期的**考试**,标记为【考试】并计入同一套
|
|
46
|
+
优先级分组。考试关键词取 exam 系词(含 examination)与中文「考试」,外加 midterm /
|
|
47
|
+
final 与 test 的组合(Final Test、Midterm Make-up Test);单独出现的 midterm / final /
|
|
48
|
+
test 不算,避免把「final report」「test your code」这类日常措辞误当成考试。一条公告
|
|
49
|
+
同时提到考试和测验时归为考试(「Final Exam 覆盖 Quiz 1-3 内容」不该算测验)。
|
|
50
|
+
- `bb-sync --json due` 的 `items[].kind` 取值扩展为 `task` / `quiz` / `exam`。
|
|
51
|
+
|
|
52
|
+
### 测试
|
|
53
|
+
|
|
54
|
+
- 新增考试提取测试:英文与中文考试公告、midterm + test 组合、日常措辞的排除,
|
|
55
|
+
以及考试优先于测验的归类。
|
|
56
|
+
|
|
57
|
+
## [1.7.0] — 2026-10-02
|
|
58
|
+
|
|
59
|
+
### 新增
|
|
60
|
+
|
|
61
|
+
- `due.md` 会从每门课公告里整理带日期的课堂测验(quiz),标记为【测验】并计入同一套
|
|
62
|
+
优先级分组;`bb-sync due` 与 `bb-sync run` 均生效。读不出日期或日期早于公告发布时间
|
|
63
|
+
的公告会被跳过,避免把复习资料里的 quiz 提及误当成待办。
|
|
64
|
+
- `bb-sync --json due` 的 `items` 新增 `kind` 字段(`task` / `quiz`),统计新增
|
|
65
|
+
`announcement_failed`;公告抓取失败不影响 To Do 待办,单独提示。
|
|
66
|
+
|
|
67
|
+
### 改进
|
|
68
|
+
|
|
69
|
+
- 类型检查门禁从 pyright `basic` 提升到 `standard`(当前代码库零报错):覆盖更多潜在
|
|
70
|
+
类型问题,且与 VS Code + Pylance 读取同一份 `[tool.pyright]` 配置,编辑器与 CI 保持一致。
|
|
71
|
+
|
|
72
|
+
### 测试
|
|
73
|
+
|
|
74
|
+
- 新增公告测验提取测试:常见日期格式(`Oct.13`、`13 November 2026`、中文日期等)、
|
|
75
|
+
月份拼写错误(`Octorber`)、跨年推断、历史公告与资料类提及的排除、Markdown 标记
|
|
76
|
+
与来源失败统计。
|
|
77
|
+
|
|
78
|
+
## [1.6.1] — 2026-10-01
|
|
79
|
+
|
|
80
|
+
### 修复
|
|
81
|
+
|
|
82
|
+
- 登录态判定改为「有没有被踢回登录 / ADFS 页」,不再依赖门户首页文案(其正文由 JS
|
|
83
|
+
异步渲染,登录态有效时会误判为未登录);点「登录」后若已直接回到 BB 门户,则跳过 ADFS 表单。
|
|
84
|
+
- 登录流程中任一步超时/异常不再逃逸成「未预期错误 + 堆栈」:统一转为退出码 3 的
|
|
85
|
+
`AuthError`,错误信息带上当前 URL,并保存现场截图与 HTML(`debug_login.png` /
|
|
86
|
+
`debug_login.html`)。
|
|
87
|
+
- 登录失败与未预期错误的提示统一引导到 GitHub Issues(附 `debug_login.html` 等现场)。
|
|
88
|
+
|
|
89
|
+
### 改进
|
|
90
|
+
|
|
91
|
+
- 下载改用**浏览器原生通道**:先用 `HEAD` 廉价探测文件名/大小做增量去重,命中已存在时
|
|
92
|
+
**不再下载文件体**;需要新下载时由 Chrome 直接流式写盘(不再整块读入内存)。浏览器
|
|
93
|
+
下载在单轮内首次失败后熔断,回退整块读取兜底。
|
|
94
|
+
- 移除 v1.6.0 引入的 urllib 直连通道,下载与登录共用同一套浏览器网络栈,避免
|
|
95
|
+
「浏览器能下、脚本直连被 TLS/代理拒绝」这类不一致,也不再刷「下载重试」日志。
|
|
96
|
+
|
|
97
|
+
### 测试
|
|
98
|
+
|
|
99
|
+
- 新增浏览器原生下载的离线测试:命中已存在不下载体、原子落盘、熔断回退、dry-run、
|
|
100
|
+
Range 嗅探扩展名与大小校验。
|
|
101
|
+
- 新增「登录超时 / 意外异常都转成 `AuthError` 并落现场」「已登录却回到门户不再误跑
|
|
102
|
+
登录流程」「URL 判定登录态」的离线测试。
|
|
103
|
+
|
|
104
|
+
## [1.6.0] — 2026-10-01
|
|
105
|
+
|
|
106
|
+
### 改进
|
|
107
|
+
|
|
108
|
+
- 下载改为流式 + 原子落盘:大文件不再整块读入内存;中断/失败只留下 `*.part`,
|
|
109
|
+
下次运行用 `Range` 续传,不再出现「半截文件被当成已存在而永久跳过」。
|
|
110
|
+
- `--dry-run` 只读取文件头即可判定文件名与去重,不再完整下载每个文件。
|
|
111
|
+
- 同一轮同步中新落盘的文件会即时写入去重索引,避免不同名同内容的大文件重复下载。
|
|
112
|
+
- 下载连接失败会按退避自动重试;流式通道不可用时回退到浏览器请求上下文。
|
|
113
|
+
- 抓取页面的固定盲等改为「等关键元素 + 网络空闲」,等待上限仍为原固定时长:
|
|
114
|
+
内容就绪的页面更早继续,空列表 / 慢页面不会更慢。
|
|
115
|
+
|
|
116
|
+
### 持续集成
|
|
117
|
+
|
|
118
|
+
- CI 质量任务扩展到 Windows,与 Ubuntu、macOS 一起运行 Ruff、Pyright 和全部离线测试。
|
|
119
|
+
|
|
120
|
+
### 测试
|
|
121
|
+
|
|
122
|
+
- 新增流式下载、原子落盘、dry-run、断点续传、重试、浏览器兜底与索引更新的离线测试。
|
|
123
|
+
- 新增等待策略的等待上限与「选择器缺失不重复等待」边界测试。
|
|
124
|
+
|
|
125
|
+
## [1.5.0] — 2026-09-28
|
|
126
|
+
|
|
127
|
+
### 新增
|
|
128
|
+
|
|
129
|
+
- 正式支持 macOS(Intel / Apple Silicon)。安装与使用文档同时覆盖 Windows PowerShell
|
|
130
|
+
和 macOS zsh / bash;凭据在 macOS 上使用系统钥匙串保存。
|
|
131
|
+
- CI 质量任务扩展到 macOS,与 Ubuntu 一起运行 Ruff、Pyright 和全部离线测试。
|
|
132
|
+
|
|
133
|
+
### 改进
|
|
134
|
+
|
|
135
|
+
- Steel 后端在 macOS 上可从 Homebrew 的 `/opt/homebrew/bin` 或 `/usr/local/bin`
|
|
136
|
+
定位 Node/npm,并同时探测系统与用户 `Applications` 下的 Chrome / Edge。
|
|
137
|
+
- macOS 启动 Steel 时使用独立进程会话,关闭终端不会再把后台服务一并结束。
|
|
138
|
+
- 下载目录位于未挂载的 `/Volumes/<名称>` 时立即给出配置错误,不再尝试在
|
|
139
|
+
`/Volumes` 下创建同名普通目录。
|
|
140
|
+
- `bb-sync doctor` 的 git、Node.js 和浏览器修复提示会按 Windows / macOS 分别给出。
|
|
141
|
+
- macOS 的 `bb-sync config edit` 在未设置 `EDITOR` 时使用系统默认文本编辑器。
|
|
142
|
+
|
|
143
|
+
### 测试
|
|
144
|
+
|
|
145
|
+
- 新增 macOS 路径探测、npm 同目录解析、后台进程脱离终端、doctor 平台提示和
|
|
146
|
+
配置编辑器契约测试。
|
|
147
|
+
|
|
148
|
+
## [1.4.0] — 2026-09-28
|
|
149
|
+
|
|
150
|
+
### 改进
|
|
151
|
+
|
|
152
|
+
- `bb-sync run` 在汇总后逐行打印待办明细(日期、课程、任务名);没有待办时打印
|
|
153
|
+
`Congratulations!`,`--json` 模式下这些诊断仍只写入 stderr。
|
|
154
|
+
|
|
155
|
+
### 修复
|
|
156
|
+
|
|
157
|
+
- 修正课程公告同步误把 `announcementInfo` 元数据当成公告正文的问题;改为读取
|
|
158
|
+
`#announcementList` 中每条的标题、发布时间、正文和发布人,避免公告都写成
|
|
159
|
+
`(无标题)` 或丢失正文;正文中的链接、图片、加粗和列表也会保留为 Markdown。
|
|
160
|
+
|
|
161
|
+
## [1.3.0] — 2026-09-28
|
|
162
|
+
|
|
163
|
+
### 改进
|
|
164
|
+
|
|
165
|
+
- `bb-sync run` 在同步课程资源后,复用同一浏览器会话扫描 Due / To Do 并更新
|
|
166
|
+
`<root>/due.md`;`--dry-run` 只统计待办,不写文件。
|
|
167
|
+
- 完整扫描后没有待办时,`due.md` 写入 `Congratulations! 🎉`;若部分课程抓取失败,
|
|
168
|
+
则明确提示结果可能不完整,避免误报全部完成。
|
|
169
|
+
|
|
170
|
+
## [1.2.0] — 2026-09-28
|
|
171
|
+
|
|
172
|
+
### 新增
|
|
173
|
+
|
|
174
|
+
- 新增 `bb-sync due`:扫描每门课程主页的 Due / To Do 模块,把全部待办整理到
|
|
175
|
+
`<root>/due.md`,按已逾期、今天、明天、未来 7 天、之后和日期未知排列。
|
|
176
|
+
- `bb-sync --json due` 输出文件路径、课程列表以及包含 ISO 截止日期的待办明细,
|
|
177
|
+
方便脚本进一步排序或提醒。
|
|
178
|
+
|
|
179
|
+
### 测试
|
|
180
|
+
|
|
181
|
+
- 新增 Due 日期解析、条目规范化去重、Markdown 优先级排序和 CLI JSON 契约测试。
|
|
182
|
+
|
|
183
|
+
## [1.1.0] — 2026-09-28
|
|
184
|
+
|
|
185
|
+
### 新增
|
|
186
|
+
|
|
187
|
+
- 普通命令成功后会检查 GitHub Releases(最多每天一次),发现新版本时在 stderr
|
|
188
|
+
提示执行 `uv tool upgrade bb-sync`;检查失败静默跳过,不影响命令结果,也不会
|
|
189
|
+
污染 `--json` 的 stdout。
|
|
190
|
+
- `bb-sync config set/unset root` 默认同步更新用户级配置,避免当前目录有项目配置时,
|
|
191
|
+
换目录运行仍使用旧下载目录;相对路径会转为绝对路径,可用 `--no-sync-home`
|
|
192
|
+
只修改当前生效文件。
|
|
193
|
+
|
|
194
|
+
### 文档
|
|
195
|
+
|
|
196
|
+
- README 精简为面向学生的安装与使用路径;开发约定移入 `AGENTS.md` 和
|
|
197
|
+
`CONTRIBUTING.md`。
|
|
198
|
+
|
|
199
|
+
### 测试
|
|
200
|
+
|
|
201
|
+
- 新增自动更新检查、缓存、禁用开关、stdout/stderr 分流,以及下载目录同步与
|
|
202
|
+
`--no-sync-home` 的测试。
|
|
203
|
+
|
|
204
|
+
## [1.0.2] — 2026-09-28
|
|
205
|
+
|
|
206
|
+
### 改进
|
|
207
|
+
|
|
208
|
+
- Steel 后端源码锚定到验证过的快照(`dacea7e2`,即上游 v0.5.4-beta 之后的
|
|
209
|
+
4 个修复),不再跟随上游 `main` 分支漂移;以后升级只改代码里的锚点。
|
|
210
|
+
- 更新 Steel 时改为「先下载、成功后再替换」:中途失败自动回滚旧版本,不会再
|
|
211
|
+
出现先把能用的安装删掉、结果装不回来的情况。
|
|
212
|
+
- `bb-sync doctor` 在已部署时显示 Steel 快照的短版本号(无元数据的老安装维持
|
|
213
|
+
原提示)。
|
|
214
|
+
|
|
215
|
+
### 修复
|
|
216
|
+
|
|
217
|
+
- 半装状态(源码在、`tsx` 依赖缺失)不再被判定为「已部署」,避免启动报错后每次
|
|
218
|
+
重试都不触发重装。
|
|
219
|
+
|
|
220
|
+
### 测试
|
|
221
|
+
|
|
222
|
+
- 新增 Steel 锚点、解压目录探测、平滑更新与失败回滚等单元测试;测试套件增至
|
|
223
|
+
112 例。
|
|
224
|
+
|
|
225
|
+
## [1.0.1] — 2026-09-28
|
|
226
|
+
|
|
227
|
+
### 修复
|
|
228
|
+
|
|
229
|
+
- 同步启动前检查下载根目录所在磁盘或网络共享是否可用。配置指向不存在的盘符
|
|
230
|
+
(如 `D:/courses`)时,CLI 现在返回退出码 4 和明确的修复提示,不再抛出创建
|
|
231
|
+
`D:\` 盘根时的 `WinError 3` 堆栈。
|
|
232
|
+
|
|
233
|
+
### 测试
|
|
234
|
+
|
|
235
|
+
- 新增下载根目录创建与磁盘不可用的单元测试;测试套件增至 103 例。
|
|
236
|
+
|
|
237
|
+
---
|
|
238
|
+
|
|
239
|
+
## [1.0.0] — 2026-09-28
|
|
240
|
+
|
|
241
|
+
首个正式版。架构定型、CLI 契约稳定、测试与 CI 就位。
|
|
242
|
+
|
|
243
|
+
### ⚠️ 破坏性变更
|
|
244
|
+
|
|
245
|
+
- **包结构重组**:顶层模块 `sync.py` / `steel_backend.py` / `paths.py` / `creds.py`
|
|
246
|
+
全部移入 `bb_sync` 包(src 布局),控制台入口由 `sync:main` 改为 `bb_sync.cli:main`。
|
|
247
|
+
已按 README 用 `uv tool install` 安装的用户,`uv tool upgrade bb-sync` 即可,
|
|
248
|
+
**配置文件与已下载的课程数据位置不变,无需迁移**。
|
|
249
|
+
- **参数形态子命令化**:旧版挂在顶层的 `bb-sync --headed` / `--dry-run` / `--doctor`
|
|
250
|
+
分别迁移为 `bb-sync run --headed`、`bb-sync run --dry-run`、`bb-sync doctor`。
|
|
251
|
+
- **不再支持 `.env`**:凭据一律只存系统钥匙串,明文 `.env` 兜底已移除。
|
|
252
|
+
|
|
253
|
+
### 新增
|
|
254
|
+
|
|
255
|
+
- **`--json` 全局开关**:结果以单个 JSON 文档输出到 stdout,日志走 stderr,
|
|
256
|
+
可直接接管道(如 `bb-sync --json course list | jq '.[].code'`)。
|
|
257
|
+
注意 `--json` 须置于子命令之前。
|
|
258
|
+
- **语义化退出码**(0–8):成功 0、未分类错误 1、用法错误 2、登录失败 3、
|
|
259
|
+
配置问题 4、网络失败 5、目标不存在 6、环境缺失 7、用户中断 8,
|
|
260
|
+
便于在 CI / 脚本中分支处理。
|
|
261
|
+
- **`course list`**:列出账号下可同步的课程,不下载任何文件。
|
|
262
|
+
- **`auth` 命令族**:`login` / `logout` / `status`,凭据管理独立成组。
|
|
263
|
+
- **同步计划预览**:开始下载前打印每门课程的落盘绝对路径,便于确认写入位置。
|
|
264
|
+
- **`docs/scripting.md`**:脚本/CI 集成的完整说明(输出通道、JSON 结构、退出码表)。
|
|
265
|
+
- **测试套件**:101 例 pytest(单元 + CLI 端到端),全离线、约 1.4 秒,
|
|
266
|
+
由 CI 在每次 push / PR 时自动运行。
|
|
267
|
+
|
|
268
|
+
### 变更
|
|
269
|
+
|
|
270
|
+
- **架构分层**:CLI → Command → Service → Domain → Browser,各层职责单一;
|
|
271
|
+
全局选项经统一的 `Context` 传递。
|
|
272
|
+
- **配置体系**:Pydantic 模型校验 + 四层优先级
|
|
273
|
+
(CLI 参数 > `BB_SYNC_*` 环境变量 > 配置文件 > 内置默认值)。
|
|
274
|
+
- **冷启动优化**:`--version` / `--help` 只加载 typer/click,
|
|
275
|
+
playwright、pydantic、rich、keyring 延迟到真正使用时才导入。
|
|
276
|
+
- **构建后端**:setuptools(`py-modules`)→ hatchling(`src/bb_sync`)。
|
|
277
|
+
- **`config set` 行级写入**:修改值时保留用户手写的注释与排版。
|
|
278
|
+
- 调试脚本统一移入 `scripts/`。
|
|
279
|
+
|
|
280
|
+
### 修复
|
|
281
|
+
|
|
282
|
+
- 修正一处导入期路径快照:`BB_SYNC_HOME` 曾被多个模块在导入时拷贝,
|
|
283
|
+
导致运行期改写在部分代码路径上失效。
|
|
284
|
+
- CI 冒烟测试:`doctor` 输出走 stderr,改用 `2>&1` 落盘供断言。
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## [0.7.0] — 2026-09-27
|
|
289
|
+
|
|
290
|
+
- 新增 `bb-sync doctor` 环境体检(git / Node / npm / 浏览器 / 网络 / 凭据 / 后端)。
|
|
291
|
+
- CI 增加 install-smoke 冒烟任务(干净容器验证安装),并支持并发取消。
|
|
292
|
+
|
|
293
|
+
## [0.6.0] — 2026-09-27
|
|
294
|
+
|
|
295
|
+
- 浏览器内核自动回退:Chrome 优先,Edge 兜底(适配仅预装 Edge 的裸机)。
|
|
296
|
+
|
|
297
|
+
## [0.5.0] — 2026-09-27
|
|
298
|
+
|
|
299
|
+
- 课程文件夹命名改用完整关键词,不再只取首词。
|
|
300
|
+
- Windows 下抑制后端控制台闪窗(`CREATE_NO_WINDOW`)。
|
|
301
|
+
- 首次运行自动生成默认配置。
|
|
302
|
+
|
|
303
|
+
## [0.4.x] — 2026-09-27
|
|
304
|
+
|
|
305
|
+
- 新增 `--root` 下载目录参数与首次运行提示,无凭据时交互录入。
|
|
306
|
+
- 首次运行自动部署 Steel 后端。
|
|
307
|
+
- 凭据改存系统钥匙串(keyring),不再落明文。
|
|
308
|
+
|
|
309
|
+
## [0.3.0] 及更早
|
|
310
|
+
|
|
311
|
+
- 支持安装为 CLI(`uv tool install`),用户级配置目录 `~/.bb-sync/`。
|
|
312
|
+
- 项目初始版本:Blackboard 课程资源自动同步。
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
[1.5.0]: https://github.com/asdukw/bb-sync/releases/tag/v1.5.0
|
|
317
|
+
[1.4.0]: https://github.com/asdukw/bb-sync/releases/tag/v1.4.0
|
|
318
|
+
[1.3.0]: https://github.com/asdukw/bb-sync/releases/tag/v1.3.0
|
|
319
|
+
[1.2.0]: https://github.com/asdukw/bb-sync/releases/tag/v1.2.0
|
|
320
|
+
[1.1.0]: https://github.com/asdukw/bb-sync/releases/tag/v1.1.0
|
|
321
|
+
[1.0.2]: https://github.com/asdukw/bb-sync/releases/tag/v1.0.2
|
|
322
|
+
[1.0.1]: https://github.com/asdukw/bb-sync/releases/tag/v1.0.1
|
|
323
|
+
[1.0.0]: https://github.com/asdukw/bb-sync/releases/tag/v1.0.0
|
|
324
|
+
[0.7.0]: https://github.com/asdukw/bb-sync/releases/tag/v0.7.0
|
|
325
|
+
[0.6.0]: https://github.com/asdukw/bb-sync/releases/tag/v0.6.0
|
|
326
|
+
[0.5.0]: https://github.com/asdukw/bb-sync/releases/tag/v0.5.0
|
|
327
|
+
[0.4.x]: https://github.com/asdukw/bb-sync/releases/tag/v0.4.1
|