Implement the bDS2 sync scripting API.
This commit is contained in:
@@ -335,47 +335,20 @@ fn active_project(db: &Database) -> Result<(Project, PathBuf)> {
|
||||
fn rebuild(db: &Database, incremental: bool) -> Result<CommandOutput> {
|
||||
let (project, data_dir) = active_project(db)?;
|
||||
if incremental {
|
||||
let (applied, imported, failed) = cli_sync::run_cli_mutation(db.conn(), || {
|
||||
let report =
|
||||
engine::metadata_diff::compute_metadata_diff(db.conn(), &data_dir, &project.id)?;
|
||||
if !report.errors.is_empty() {
|
||||
return Err(engine::EngineError::Validation(report.errors.join("; ")));
|
||||
}
|
||||
for item in &report.diffs {
|
||||
engine::metadata_diff::repair_metadata_diff_item(
|
||||
db.conn(),
|
||||
&data_dir,
|
||||
&project.id,
|
||||
engine::metadata_diff::RepairDirection::FileToDatabase,
|
||||
item,
|
||||
)?;
|
||||
}
|
||||
let filesystem_orphans = report
|
||||
.orphans
|
||||
.iter()
|
||||
.filter(|orphan| orphan.reason == "file_without_db_entry")
|
||||
.collect::<Vec<_>>();
|
||||
let mut imported = 0;
|
||||
let mut failed = 0;
|
||||
for orphan in filesystem_orphans {
|
||||
match engine::metadata_diff::import_orphan_file(
|
||||
db.conn(),
|
||||
&data_dir,
|
||||
&project.id,
|
||||
orphan,
|
||||
) {
|
||||
Ok(()) => imported += 1,
|
||||
Err(_) => failed += 1,
|
||||
}
|
||||
}
|
||||
if !report.diffs.is_empty() || imported > 0 {
|
||||
let report = cli_sync::run_cli_mutation(db.conn(), || {
|
||||
let report = engine::rebuild::rebuild_incremental(db.conn(), &data_dir, &project.id)?;
|
||||
if report.differences_applied > 0 || report.orphans_imported > 0 {
|
||||
emit_bulk(&project.id);
|
||||
}
|
||||
Ok((report.diffs.len(), imported, failed))
|
||||
Ok(report)
|
||||
})?;
|
||||
return Ok(output(
|
||||
"Applied incremental filesystem changes",
|
||||
json!({"differences_applied": applied, "orphans_imported": imported, "orphans_failed": failed}),
|
||||
json!({
|
||||
"differences_applied": report.differences_applied,
|
||||
"orphans_imported": report.orphans_imported,
|
||||
"orphans_failed": report.orphans_failed,
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
|
||||
@@ -16,11 +16,10 @@ mod tests {
|
||||
use crate::db::Database;
|
||||
use crate::db::schema::{
|
||||
ai_catalog_meta, ai_endpoint_models, ai_model_modalities, ai_models, ai_providers,
|
||||
chat_conversations,
|
||||
chat_messages, db_notifications, dismissed_duplicate_pairs, embedding_keys,
|
||||
generated_file_hashes, import_definitions, mcp_proposals, media, media_translations,
|
||||
post_links, post_media, post_translations, posts, projects, scripts, settings, tags,
|
||||
templates,
|
||||
chat_conversations, chat_messages, db_notifications, dismissed_duplicate_pairs,
|
||||
embedding_keys, generated_file_hashes, import_definitions, mcp_proposals, media,
|
||||
media_translations, post_links, post_media, post_translations, posts, projects, scripts,
|
||||
settings, tags, templates,
|
||||
};
|
||||
use diesel::prelude::*;
|
||||
use diesel_migrations::MigrationHarness;
|
||||
|
||||
@@ -29,6 +29,51 @@ pub struct FullRebuildReport {
|
||||
pub errors: Vec<String>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, PartialEq, Eq)]
|
||||
pub struct IncrementalRebuildReport {
|
||||
pub differences_applied: usize,
|
||||
pub orphans_imported: usize,
|
||||
pub orphans_failed: usize,
|
||||
}
|
||||
|
||||
/// Apply portable filesystem changes to one project's cache database.
|
||||
pub fn rebuild_incremental(
|
||||
conn: &Connection,
|
||||
data_dir: &Path,
|
||||
project_id: &str,
|
||||
) -> EngineResult<IncrementalRebuildReport> {
|
||||
let report = super::metadata_diff::compute_metadata_diff(conn, data_dir, project_id)?;
|
||||
if !report.errors.is_empty() {
|
||||
return Err(crate::engine::EngineError::Validation(
|
||||
report.errors.join("; "),
|
||||
));
|
||||
}
|
||||
for item in &report.diffs {
|
||||
super::metadata_diff::repair_metadata_diff_item(
|
||||
conn,
|
||||
data_dir,
|
||||
project_id,
|
||||
super::metadata_diff::RepairDirection::FileToDatabase,
|
||||
item,
|
||||
)?;
|
||||
}
|
||||
let mut result = IncrementalRebuildReport {
|
||||
differences_applied: report.diffs.len(),
|
||||
..Default::default()
|
||||
};
|
||||
for orphan in report
|
||||
.orphans
|
||||
.iter()
|
||||
.filter(|orphan| orphan.reason == "file_without_db_entry")
|
||||
{
|
||||
match super::metadata_diff::import_orphan_file(conn, data_dir, project_id, orphan) {
|
||||
Ok(()) => result.orphans_imported += 1,
|
||||
Err(_) => result.orphans_failed += 1,
|
||||
}
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// Progress callback: (percent 0.0..1.0, phase description).
|
||||
pub type ProgressFn = Arc<dyn Fn(f32, &str) + Send + Sync>;
|
||||
|
||||
|
||||
@@ -1239,6 +1239,64 @@ impl CoreHost {
|
||||
Ok(Value::Bool(true))
|
||||
}
|
||||
|
||||
fn sync(&self, method: &str, args: &[Value]) -> HostResult<Value> {
|
||||
if method == "check_availability" {
|
||||
return Ok(std::process::Command::new("git")
|
||||
.arg("--version")
|
||||
.output()
|
||||
.is_ok()
|
||||
.into());
|
||||
}
|
||||
if self.offline_mode && matches!(method, "fetch" | "pull" | "push") {
|
||||
return Err(format!("Git {method} is unavailable in airplane mode").into());
|
||||
}
|
||||
let git = engine::git::GitEngine::new(&self.data_dir);
|
||||
let cancelled = || {
|
||||
self.task_manager
|
||||
.as_ref()
|
||||
.zip(self.task_id)
|
||||
.is_some_and(|(manager, id)| manager.is_cancelled(id))
|
||||
};
|
||||
match method {
|
||||
"get_repo_state" | "get_remote_state" => {
|
||||
Ok(public_git_repository(git.repository().map_err(text)?))
|
||||
}
|
||||
"get_status" => Ok(json!({
|
||||
"files": git.status().map_err(text)?.into_iter().map(public_git_status).collect::<Vec<_>>(),
|
||||
})),
|
||||
"get_history" => {
|
||||
let repository = git.repository().map_err(text)?;
|
||||
let commits = match repository.current_branch {
|
||||
Some(branch) => git.history(&branch).map_err(text)?,
|
||||
None => Vec::new(),
|
||||
};
|
||||
Ok(json!({
|
||||
"commits": commits.into_iter().map(public_git_commit).collect::<Vec<_>>(),
|
||||
}))
|
||||
}
|
||||
"fetch" => {
|
||||
let result = git.fetch(cancelled, |_| {}).map_err(text)?;
|
||||
Ok(json!({"updated": true, "output": result.output}))
|
||||
}
|
||||
"pull" => {
|
||||
let result = git.pull(cancelled, |_| {}).map_err(text)?;
|
||||
let db = self.database()?;
|
||||
engine::rebuild::rebuild_incremental(db.conn(), &self.data_dir, &self.project_id)?;
|
||||
Ok(json!({"updated": true, "output": result.output}))
|
||||
}
|
||||
"push" => {
|
||||
let result = git.push(cancelled, |_| {}).map_err(text)?;
|
||||
Ok(json!({"updated": true, "output": result.output}))
|
||||
}
|
||||
"commit_all" => {
|
||||
let message = string_arg(args, 0)?;
|
||||
let result = git.commit_all(message).map_err(text)?;
|
||||
Ok(json!({"message": message, "output": result.output}))
|
||||
}
|
||||
_ => Err(format!("unknown sync capability: {method}").into()),
|
||||
}
|
||||
}
|
||||
|
||||
fn publish(&self, method: &str, args: &[Value]) -> HostResult<Value> {
|
||||
if method != "upload_site" {
|
||||
return Err(format!("unknown publish capability: {method}").into());
|
||||
@@ -1492,6 +1550,7 @@ impl HostApi for CoreHost {
|
||||
"templates" => self.templates(method, &arguments),
|
||||
"tags" => self.tags(method, &arguments),
|
||||
"tasks" => self.tasks(method, &arguments),
|
||||
"sync" => self.sync(method, &arguments),
|
||||
"publish" => self.publish(method, &arguments),
|
||||
"chat" => self.chat(method, &arguments),
|
||||
"embeddings" => self.embeddings(method, &arguments),
|
||||
@@ -1587,6 +1646,54 @@ fn public_tasks(values: Vec<TaskSnapshot>) -> HostResult<Value> {
|
||||
.map(Value::Array)
|
||||
}
|
||||
|
||||
fn public_git_repository(value: engine::git::GitRepository) -> Value {
|
||||
json!({
|
||||
"is_initialized": value.is_initialized,
|
||||
"remote_url": value.remote_url,
|
||||
"provider": value.provider.map(|provider| json!({"kind": match provider {
|
||||
engine::git::GitProvider::GitHub => "github",
|
||||
engine::git::GitProvider::GitLab => "gitlab",
|
||||
engine::git::GitProvider::GiteaForgejo => "gitea_forgejo",
|
||||
}})),
|
||||
"current_branch": value.current_branch,
|
||||
"has_lfs": value.has_lfs,
|
||||
})
|
||||
}
|
||||
|
||||
fn public_git_status(value: engine::git::GitFileStatus) -> Value {
|
||||
let mut result = Map::new();
|
||||
result.insert("path".into(), value.path.into());
|
||||
if let Some(old_path) = value.old_path {
|
||||
result.insert("old_path".into(), old_path.into());
|
||||
}
|
||||
result.insert(
|
||||
"status".into(),
|
||||
match value.kind {
|
||||
engine::git::FileStatusKind::Added => "added",
|
||||
engine::git::FileStatusKind::Modified => "modified",
|
||||
engine::git::FileStatusKind::Deleted => "deleted",
|
||||
engine::git::FileStatusKind::Renamed => "renamed",
|
||||
engine::git::FileStatusKind::Untracked => "untracked",
|
||||
}
|
||||
.into(),
|
||||
);
|
||||
Value::Object(result)
|
||||
}
|
||||
|
||||
fn public_git_commit(value: engine::git::GitCommit) -> Value {
|
||||
json!({
|
||||
"hash": value.hash,
|
||||
"subject": value.subject,
|
||||
"author": value.author,
|
||||
"date": value.date,
|
||||
"sync_status": {"kind": match value.sync_status {
|
||||
engine::git::SyncStatus::LocalOnly => "local_only",
|
||||
engine::git::SyncStatus::RemoteOnly => "remote_only",
|
||||
engine::git::SyncStatus::Both => "both",
|
||||
}},
|
||||
})
|
||||
}
|
||||
|
||||
fn public_metadata(data_dir: &Path) -> HostResult<Value> {
|
||||
let metadata = engine::meta::read_project_json(data_dir)?;
|
||||
Ok(json!({
|
||||
@@ -1862,6 +1969,255 @@ fn one_shot_json(value: engine::ai::OneShotResponse) -> HostResult<Value> {
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::scripting::{ExecutionControl, ExecutionKind, execute_with_host};
|
||||
use std::fs;
|
||||
use std::process::Command;
|
||||
|
||||
struct SyncFixture {
|
||||
_temp: tempfile::TempDir,
|
||||
db_path: PathBuf,
|
||||
data_dir: PathBuf,
|
||||
remote_dir: PathBuf,
|
||||
project_id: String,
|
||||
}
|
||||
|
||||
impl SyncFixture {
|
||||
fn new() -> Self {
|
||||
let temp = tempfile::tempdir().unwrap();
|
||||
let db_path = temp.path().join("ruds.db");
|
||||
let data_dir = temp.path().join("project");
|
||||
let remote_dir = temp.path().join("remote.git");
|
||||
let upstream_dir = temp.path().join("upstream");
|
||||
let db = Database::open(&db_path).unwrap();
|
||||
db.migrate().unwrap();
|
||||
crate::db::fts::ensure_fts_tables(db.conn()).unwrap();
|
||||
let project = engine::project::create_project(
|
||||
db.conn(),
|
||||
"Active",
|
||||
Some(data_dir.to_str().unwrap()),
|
||||
)
|
||||
.unwrap();
|
||||
engine::project::set_active_project(db.conn(), &project.id).unwrap();
|
||||
drop(db);
|
||||
|
||||
git(&data_dir, &["init", "-b", "master"]);
|
||||
configure_git(&data_dir);
|
||||
git(&data_dir, &["add", "-A"]);
|
||||
git(&data_dir, &["commit", "-m", "Initial project"]);
|
||||
git(
|
||||
temp.path(),
|
||||
&[
|
||||
"init",
|
||||
"--bare",
|
||||
"-b",
|
||||
"master",
|
||||
remote_dir.to_str().unwrap(),
|
||||
],
|
||||
);
|
||||
git(
|
||||
&data_dir,
|
||||
&["remote", "add", "origin", remote_dir.to_str().unwrap()],
|
||||
);
|
||||
git(&data_dir, &["push", "-u", "origin", "master"]);
|
||||
git(
|
||||
temp.path(),
|
||||
&[
|
||||
"clone",
|
||||
remote_dir.to_str().unwrap(),
|
||||
upstream_dir.to_str().unwrap(),
|
||||
],
|
||||
);
|
||||
configure_git(&upstream_dir);
|
||||
let mut metadata = engine::meta::read_project_json(&upstream_dir).unwrap();
|
||||
metadata.name = "Pulled Name".into();
|
||||
engine::meta::write_project_json(&upstream_dir, &metadata).unwrap();
|
||||
git(&upstream_dir, &["add", "-A"]);
|
||||
git(&upstream_dir, &["commit", "-m", "Update project name"]);
|
||||
git(&upstream_dir, &["push", "origin", "master"]);
|
||||
fs::write(data_dir.join("pending.txt"), "pending").unwrap();
|
||||
|
||||
Self {
|
||||
_temp: temp,
|
||||
db_path,
|
||||
data_dir,
|
||||
remote_dir,
|
||||
project_id: project.id,
|
||||
}
|
||||
}
|
||||
|
||||
fn host(&self, offline: bool) -> CoreHost {
|
||||
CoreHost::new(&self.db_path, &self.project_id, &self.data_dir)
|
||||
.with_offline_mode(offline)
|
||||
}
|
||||
}
|
||||
|
||||
fn configure_git(dir: &Path) {
|
||||
git(dir, &["config", "user.name", "Lua Test"]);
|
||||
git(dir, &["config", "user.email", "lua@example.invalid"]);
|
||||
}
|
||||
|
||||
fn git(dir: &Path, args: &[&str]) -> String {
|
||||
let output = Command::new("git")
|
||||
.args(args)
|
||||
.current_dir(dir)
|
||||
.env("GIT_TERMINAL_PROMPT", "0")
|
||||
.output()
|
||||
.unwrap();
|
||||
assert!(
|
||||
output.status.success(),
|
||||
"git {} failed: {}",
|
||||
args.join(" "),
|
||||
String::from_utf8_lossy(&output.stderr)
|
||||
);
|
||||
String::from_utf8(output.stdout).unwrap().trim().to_owned()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_namespace_runs_every_bds2_method_and_reconciles_pull() {
|
||||
let fixture = SyncFixture::new();
|
||||
let result = execute_with_host(
|
||||
r#"
|
||||
function main()
|
||||
local status = bds.sync.get_status()
|
||||
local history = bds.sync.get_history()
|
||||
return {
|
||||
available = bds.sync.check_availability(),
|
||||
repo = bds.sync.get_repo_state(),
|
||||
remote = bds.sync.get_remote_state(),
|
||||
status = status,
|
||||
history = history,
|
||||
fetched = bds.sync.fetch(),
|
||||
pulled = bds.sync.pull(),
|
||||
committed = bds.sync.commit_all("Lua commit"),
|
||||
pushed = bds.sync.push(),
|
||||
}
|
||||
end
|
||||
"#,
|
||||
"main",
|
||||
&Value::Null,
|
||||
ExecutionKind::Utility,
|
||||
&ExecutionControl::default(),
|
||||
Arc::new(fixture.host(false)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.value["available"], true);
|
||||
assert_eq!(result.value["repo"]["is_initialized"], true);
|
||||
assert_eq!(result.value["remote"], result.value["repo"]);
|
||||
assert!(
|
||||
result.value["status"]["files"]
|
||||
.as_array()
|
||||
.unwrap()
|
||||
.iter()
|
||||
.any(|file| file == &json!({"path":"pending.txt","status":"untracked"}))
|
||||
);
|
||||
let commit = &result.value["history"]["commits"][0];
|
||||
assert!(commit["date"].as_str().is_some_and(|date| date.len() == 10));
|
||||
assert!(commit["sync_status"]["kind"].is_string());
|
||||
assert_eq!(result.value["fetched"]["updated"], true);
|
||||
assert_eq!(result.value["pulled"]["updated"], true);
|
||||
assert_eq!(result.value["committed"]["message"], "Lua commit");
|
||||
assert_eq!(result.value["pushed"]["updated"], true);
|
||||
|
||||
let db = Database::open(&fixture.db_path).unwrap();
|
||||
assert_eq!(
|
||||
project::get_project_by_id(db.conn(), &fixture.project_id)
|
||||
.unwrap()
|
||||
.name,
|
||||
"Pulled Name"
|
||||
);
|
||||
assert_eq!(
|
||||
git(&fixture.remote_dir, &["log", "-1", "--format=%s"]),
|
||||
"Lua commit"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_namespace_uses_nil_for_non_repository_failures() {
|
||||
let temp = tempfile::tempdir().unwrap();
|
||||
let data_dir = temp.path().join("not-a-repository");
|
||||
fs::create_dir(&data_dir).unwrap();
|
||||
let result = execute_with_host(
|
||||
r#"
|
||||
function main()
|
||||
return {
|
||||
repo = bds.sync.get_repo_state(),
|
||||
remote = bds.sync.get_remote_state(),
|
||||
status = bds.sync.get_status(),
|
||||
history = bds.sync.get_history(),
|
||||
fetched = bds.sync.fetch(),
|
||||
pulled = bds.sync.pull(),
|
||||
pushed = bds.sync.push(),
|
||||
committed = bds.sync.commit_all("no repository"),
|
||||
}
|
||||
end
|
||||
"#,
|
||||
"main",
|
||||
&Value::Null,
|
||||
ExecutionKind::Utility,
|
||||
&ExecutionControl::default(),
|
||||
Arc::new(CoreHost::new(
|
||||
temp.path().join("missing.db"),
|
||||
"p1",
|
||||
&data_dir,
|
||||
)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(result.value["repo"]["is_initialized"], false);
|
||||
assert_eq!(result.value["remote"], result.value["repo"]);
|
||||
assert_eq!(result.value["history"], json!({"commits": []}));
|
||||
for key in ["status", "fetched", "pulled", "pushed", "committed"] {
|
||||
assert!(result.value[key].is_null(), "{key} was not nil");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn sync_namespace_airplane_gate_prevents_network_commands_and_rejects_blank_commit() {
|
||||
let fixture = SyncFixture::new();
|
||||
git(&fixture.data_dir, &["add", "pending.txt"]);
|
||||
git(&fixture.data_dir, &["commit", "-m", "Local only"]);
|
||||
let local_head = git(&fixture.data_dir, &["rev-parse", "HEAD"]);
|
||||
let tracking_head = git(
|
||||
&fixture.data_dir,
|
||||
&["rev-parse", "refs/remotes/origin/master"],
|
||||
);
|
||||
let remote_head = git(&fixture.remote_dir, &["rev-parse", "refs/heads/master"]);
|
||||
|
||||
let result = execute_with_host(
|
||||
r#"
|
||||
function main()
|
||||
return {
|
||||
fetched = bds.sync.fetch(),
|
||||
pulled = bds.sync.pull(),
|
||||
pushed = bds.sync.push(),
|
||||
committed = bds.sync.commit_all(" "),
|
||||
}
|
||||
end
|
||||
"#,
|
||||
"main",
|
||||
&Value::Null,
|
||||
ExecutionKind::Utility,
|
||||
&ExecutionControl::default(),
|
||||
Arc::new(fixture.host(true)),
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
for key in ["fetched", "pulled", "pushed", "committed"] {
|
||||
assert!(result.value[key].is_null(), "{key} was not nil");
|
||||
}
|
||||
assert_eq!(git(&fixture.data_dir, &["rev-parse", "HEAD"]), local_head);
|
||||
assert_eq!(
|
||||
git(
|
||||
&fixture.data_dir,
|
||||
&["rev-parse", "refs/remotes/origin/master"],
|
||||
),
|
||||
tracking_head
|
||||
);
|
||||
assert_eq!(
|
||||
git(&fixture.remote_dir, &["rev-parse", "refs/heads/master"]),
|
||||
remote_head
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn project_host_round_trips_engines_and_enforces_scope_and_failure_values() {
|
||||
|
||||
@@ -376,6 +376,23 @@ fn field_description(field: &str) -> &'static str {
|
||||
"slug" => "URL-safe record identifier.",
|
||||
"description" => "Human-readable description.",
|
||||
"status" => "Current lifecycle state.",
|
||||
"kind" => "Public enum value.",
|
||||
"path" => "Current repository-relative path.",
|
||||
"old_path" => "Previous repository-relative path for a rename.",
|
||||
"files" => "Changed repository paths.",
|
||||
"commits" => "Commit history entries.",
|
||||
"hash" => "Git object identifier.",
|
||||
"subject" => "Commit subject.",
|
||||
"author" => "Commit author.",
|
||||
"date" => "ISO-8601 commit date.",
|
||||
"sync_status" => "Local/remote presence classification.",
|
||||
"current_branch" => "Checked-out branch name.",
|
||||
"has_lfs" => "Whether Git LFS tracking is configured.",
|
||||
"is_initialized" => "Whether the project folder is a Git repository.",
|
||||
"provider" => "Hosting provider inferred from the remote URL.",
|
||||
"remote_url" => "Configured origin URL.",
|
||||
"output" => "Git command output.",
|
||||
"updated" => "Whether the Git network command completed successfully.",
|
||||
"progress" => "Completion value reported by the task.",
|
||||
"message" => "Latest user-facing task message.",
|
||||
"created_at" => "Creation timestamp.",
|
||||
@@ -403,7 +420,6 @@ fn field_description(field: &str) -> &'static str {
|
||||
"file_path" => "Stored media file path.",
|
||||
"alt" => "Alternative text for the media.",
|
||||
"caption" => "Media caption.",
|
||||
"kind" => "Script or template kind.",
|
||||
"entrypoint" => "Lua function invoked by the runtime.",
|
||||
"color" => "Optional display color.",
|
||||
"post_template_slug" => "Template selected for tagged posts.",
|
||||
|
||||
@@ -463,6 +463,7 @@ mod tests {
|
||||
"projects",
|
||||
"publish",
|
||||
"scripts",
|
||||
"sync",
|
||||
"tags",
|
||||
"tasks",
|
||||
"templates",
|
||||
@@ -473,7 +474,7 @@ mod tests {
|
||||
r#"
|
||||
function main()
|
||||
return {
|
||||
sync = bds.sync,
|
||||
sync = type(bds.sync),
|
||||
embeddings = type(bds.embeddings),
|
||||
report_progress = type(bds.report_progress),
|
||||
post_search = type(bds.posts.search),
|
||||
@@ -494,6 +495,7 @@ mod tests {
|
||||
"post_search": "function",
|
||||
"app_toast": "function",
|
||||
"embeddings": "table",
|
||||
"sync": "table",
|
||||
})
|
||||
);
|
||||
}
|
||||
@@ -515,6 +517,7 @@ mod tests {
|
||||
bds.tags.get_all(),
|
||||
bds.tasks.status_snapshot(),
|
||||
bds.publish.upload_site({}),
|
||||
bds.sync.check_availability(),
|
||||
bds.chat.detect_post_language("title", "body"),
|
||||
bds.embeddings.get_progress(),
|
||||
}
|
||||
@@ -528,8 +531,8 @@ mod tests {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(execution.value.as_array().unwrap().len(), 12);
|
||||
assert_eq!(host.0.lock().unwrap().len(), 12);
|
||||
assert_eq!(execution.value.as_array().unwrap().len(), 13);
|
||||
assert_eq!(host.0.lock().unwrap().len(), 13);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
@@ -352,7 +352,9 @@ fn user_guide_path() -> PathBuf {
|
||||
}
|
||||
|
||||
fn root_document_path(name: &str) -> PathBuf {
|
||||
Path::new(env!("CARGO_MANIFEST_DIR")).join("../..").join(name)
|
||||
Path::new(env!("CARGO_MANIFEST_DIR"))
|
||||
.join("../..")
|
||||
.join(name)
|
||||
}
|
||||
|
||||
pub fn parse_document(source: &str) -> ParsedDocument {
|
||||
|
||||
Reference in New Issue
Block a user