mirror of
https://github.com/farion1231/cc-switch.git
synced 2026-07-31 02:51:21 +08:00
fix(ci): run backend checks on Windows/macOS and repair platform-gated tests (#5138)
* fix(ci): run backend checks on Windows/macOS and repair platform-gated tests
The backend CI job ran only on ubuntu-22.04, so every #[cfg(target_os =
"windows")] / macOS path — tests and clippy lints alike — was never
compiled or run. As a result main shipped 8 failing Windows unit tests and
a hard `cargo clippy -- -D warnings` failure on Windows, all invisible to
CI because it only builds and tests Linux.
Changes:
- ci: run the backend job on a {ubuntu-22.04, windows-latest, macos-latest}
matrix (fail-fast: false); gate the apt install step on runner.os ==
'Linux' and use `shell: bash` for the dist placeholder so it works on all
three runners.
- misc.rs: fix 6 stale `anchored_upgrade_windows` tests. Commit 5092fe51
removed codex from `prefers_official_update`, so codex now anchors to the
package manager with no `codex update ||` prefix; update the five
package-manager expectations accordingly, and retarget the no-sibling
"official-update-without-fallback" test to `claude` (still in the list) so
that branch stays covered instead of being silently dropped.
- codex_state_db.rs / codex_history_migration.rs: the two sqlite_home tests
built TOML basic strings from Windows paths, whose backslashes are invalid
escape sequences and made the override fail to parse; switch to TOML
literal (single-quoted) strings so the path is taken verbatim.
- clippy (13 Windows-only warnings): move `use std::io::Write` into the
#[cfg(unix)] block that actually uses it; convert 3 unneeded `return`s in
Windows-gated tail positions to expressions; mark 9 POSIX-shell helpers
#[cfg_attr(windows, allow(dead_code))] since they are used only by the
macOS/Linux terminal launchers.
Verified locally (Windows 11, Rust 1.95.0):
cargo test --lib → 1748 passed; 0 failed (was 1740/8)
cargo clippy -- -D warnings → clean (was 13 errors)
cargo fmt --check → clean
Co-Authored-By: Claude <noreply@anthropic.com>
* fix(skills): resolve home via get_home_dir so tests isolate on Windows
services/skill.rs called dirs::home_dir() directly in five places. On
Windows dirs::home_dir() resolves through the Known Folder API and
ignores HOME/USERPROFILE, so the CC_SWITCH_TEST_HOME override set by the
test harness never applied: the skill_sync integration tests scanned the
runner's real user profile, found no skills, and failed (the first panic
then poisoned the shared test mutex, cascading to all seven). On Unix
the harness also sets HOME, which dirs::home_dir() honors, so the suite
passed there by accident.
Route all five call sites through crate::config::get_home_dir(), the
crate-wide home resolver that prefers CC_SWITCH_TEST_HOME. The three
now-unreachable GET_HOME_DIR_FAILED error branches are dropped:
get_home_dir() is infallible, matching every other config-dir resolver.
Production behavior is unchanged (CC_SWITCH_TEST_HOME is unset outside
tests, so get_home_dir falls through to dirs::home_dir).
Add a regression test that discriminates on every platform by pointing
CC_SWITCH_TEST_HOME at a temp dir different from $HOME; it is marked
#[serial_test::serial] to stay mutually exclusive with the other tests
mutating the same process-global variable. Verified the test fails
against the old code on macOS with the same failure mode as Windows CI.
---------
Co-authored-by: Claude <noreply@anthropic.com>
Co-authored-by: Jason <farion1231@gmail.com>
This commit is contained in:
@@ -374,20 +374,15 @@ fn parse_branch_from_source_url(source_url: Option<&str>) -> Option<String> {
|
||||
|
||||
/// 获取 `~/.agents/skills/` 目录(存在时返回)
|
||||
fn get_agents_skills_dir() -> Option<PathBuf> {
|
||||
dirs::home_dir()
|
||||
.map(|h| h.join(".agents").join("skills"))
|
||||
.filter(|p| p.exists())
|
||||
let dir = crate::config::get_home_dir().join(".agents").join("skills");
|
||||
dir.exists().then_some(dir)
|
||||
}
|
||||
|
||||
/// 解析 `~/.agents/.skill-lock.json`,返回 skill_name -> 仓库信息
|
||||
fn parse_agents_lock() -> HashMap<String, LockRepoInfo> {
|
||||
let path = match dirs::home_dir() {
|
||||
Some(h) => h.join(".agents").join(".skill-lock.json"),
|
||||
None => {
|
||||
log::warn!("无法获取 HOME 目录,跳过解析 agents lock 文件");
|
||||
return HashMap::new();
|
||||
}
|
||||
};
|
||||
let path = crate::config::get_home_dir()
|
||||
.join(".agents")
|
||||
.join(".skill-lock.json");
|
||||
let content = match fs::read_to_string(&path) {
|
||||
Ok(c) => c,
|
||||
Err(e) => {
|
||||
@@ -482,12 +477,7 @@ impl SkillService {
|
||||
let dir = match location {
|
||||
SkillStorageLocation::CcSwitch => get_app_config_dir().join("skills"),
|
||||
SkillStorageLocation::Unified => {
|
||||
let home = dirs::home_dir().context(format_skill_error(
|
||||
"GET_HOME_DIR_FAILED",
|
||||
&[],
|
||||
Some("checkPermission"),
|
||||
))?;
|
||||
home.join(".agents").join("skills")
|
||||
crate::config::get_home_dir().join(".agents").join("skills")
|
||||
}
|
||||
};
|
||||
fs::create_dir_all(&dir)?;
|
||||
@@ -538,12 +528,10 @@ impl SkillService {
|
||||
}
|
||||
}
|
||||
|
||||
// 默认路径:回退到用户主目录下的标准位置
|
||||
let home = dirs::home_dir().context(format_skill_error(
|
||||
"GET_HOME_DIR_FAILED",
|
||||
&[],
|
||||
Some("checkPermission"),
|
||||
))?;
|
||||
// 默认路径:回退到用户主目录下的标准位置。
|
||||
// 必须走 get_home_dir()(可被 CC_SWITCH_TEST_HOME 覆盖):Windows 上 dirs::home_dir()
|
||||
// 走 Known Folder API,测试无法隔离真实用户目录。
|
||||
let home = crate::config::get_home_dir();
|
||||
|
||||
Ok(match app {
|
||||
AppType::Claude => home.join(".claude").join("skills"),
|
||||
@@ -1167,8 +1155,7 @@ impl SkillService {
|
||||
let new_dir = match target {
|
||||
SkillStorageLocation::CcSwitch => get_app_config_dir().join("skills"),
|
||||
SkillStorageLocation::Unified => {
|
||||
let home = dirs::home_dir().context("Cannot determine home directory")?;
|
||||
home.join(".agents").join("skills")
|
||||
crate::config::get_home_dir().join(".agents").join("skills")
|
||||
}
|
||||
};
|
||||
fs::create_dir_all(&new_dir)?;
|
||||
@@ -3069,6 +3056,36 @@ mod tests {
|
||||
.expect("write SKILL.md");
|
||||
}
|
||||
|
||||
#[test]
|
||||
// serial:与 backup/s3_sync/deeplink 等同样读写进程级 CC_SWITCH_TEST_HOME 的测试互斥,
|
||||
// EnvGuard 只负责恢复不提供互斥。
|
||||
#[serial_test::serial]
|
||||
fn get_app_skills_dir_honors_test_home_override() {
|
||||
// 回归:曾直呼 dirs::home_dir() 绕过 CC_SWITCH_TEST_HOME——Unix 上碰巧跟 $HOME
|
||||
// 一致所以测试能过,Windows 上 dirs 走 Known Folder API,测试隔离整体失效
|
||||
// (tests/skill_sync.rs 扫到 runner 真实用户目录)。
|
||||
struct EnvGuard(Option<std::ffi::OsString>);
|
||||
impl Drop for EnvGuard {
|
||||
fn drop(&mut self) {
|
||||
match self.0.take() {
|
||||
Some(value) => std::env::set_var("CC_SWITCH_TEST_HOME", value),
|
||||
None => std::env::remove_var("CC_SWITCH_TEST_HOME"),
|
||||
}
|
||||
}
|
||||
}
|
||||
let temp = tempdir().expect("tempdir");
|
||||
let _guard = EnvGuard(std::env::var_os("CC_SWITCH_TEST_HOME"));
|
||||
std::env::set_var("CC_SWITCH_TEST_HOME", temp.path());
|
||||
|
||||
let dir =
|
||||
SkillService::get_app_skills_dir(&AppType::Claude).expect("resolve claude skills dir");
|
||||
assert!(
|
||||
dir.starts_with(temp.path()),
|
||||
"skills dir must live under the overridden test home, got {}",
|
||||
dir.display()
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_skill_source_dir_returns_repo_root_for_root_level_skill() {
|
||||
let temp = tempdir().expect("tempdir");
|
||||
|
||||
Reference in New Issue
Block a user