feat: publish Dever core with project scaffolding and versioned AI skills

This commit is contained in:
Antigravity committed 2026-10-04 13:37:30 +00:00
1 parent 70fa73cdc2
commit ac458ffa7f
960 files changed
+221319 -1163

No files matched your search

+451
View File
@@ -0,0 +1,451 @@
use std::fs;
use std::path::{Path, PathBuf};
use std::process::{Command, Output, Stdio};
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::Duration;
#[path = "../dever-tests/tests/support/process.rs"]
pub mod process;
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[path = "support/llvm_pack.rs"]
pub mod llvm_pack;
static NEXT_DIRECTORY: AtomicU64 = AtomicU64::new(0);
struct TemporaryProject(PathBuf);
impl TemporaryProject {
fn new() -> Self {
let suffix = NEXT_DIRECTORY.fetch_add(1, Ordering::Relaxed);
let root =
std::env::temp_dir().join(format!("dever-cms-project-{}-{suffix}", std::process::id()));
fs::create_dir(&root).unwrap();
Self(root)
}
fn copy_from(source: &Path) -> Self {
let project = Self::new();
copy_directory(&source.join("config"), &project.path().join("config"));
copy_directory(&source.join("module"), &project.path().join("module"));
let tests = source.join("test");
if tests.exists() {
copy_directory(&tests, &project.path().join("test"));
}
fs::create_dir(project.path().join("data")).unwrap();
project
}
fn package(source: &Path, executable: &Path) -> Self {
let project = Self::new();
copy_directory(&source.join("config"), &project.path().join("config"));
fs::copy(executable, project.path().join("cms-app")).unwrap();
project
}
fn path(&self) -> &Path {
&self.0
}
fn block_deployment_database(&self) {
// Package metadata needs valid JSON. A directory as the configured
// database proves tests use their own SQLite configuration instead.
fs::create_dir(self.path().join("data/deployment.db")).unwrap();
fs::write(
self.path().join("config/setting.json"),
r#"{"database":{"default":{"type":"sqlite","path":"data/deployment.db"}}}"#,
)
.unwrap();
}
}
impl Drop for TemporaryProject {
fn drop(&mut self) {
let _ = fs::remove_dir_all(&self.0);
}
}
fn copy_directory(source: &Path, target: &Path) {
fs::create_dir(target).unwrap();
for entry in fs::read_dir(source).unwrap() {
let entry = entry.unwrap();
let source = entry.path();
let target = target.join(entry.file_name());
if entry.file_type().unwrap().is_dir() {
copy_directory(&source, &target);
} else {
fs::copy(source, target).unwrap();
}
}
}
fn dever(project: &Path, action: &str, arguments: &[&str]) -> Output {
dever_with_pid(project, action, arguments).1
}
fn dever_with_pid(project: &Path, action: &str, arguments: &[&str]) -> (u32, Output) {
output_with_pid(
Command::new(env!("CARGO_BIN_EXE_dever"))
.arg(action)
.arg(project)
.args(arguments),
)
}
fn output_with_pid(command: &mut Command) -> (u32, Output) {
let capture = TemporaryProject::new();
let stdout = capture.path().join("stdout");
let stderr = capture.path().join("stderr");
let mut child = command
.env_clear()
.stdout(Stdio::from(fs::File::create(&stdout).unwrap()))
.stderr(Stdio::from(fs::File::create(&stderr).unwrap()))
.spawn()
.unwrap();
let pid = child.id();
let status = process::wait(&mut child, Duration::from_secs(180)).unwrap();
(
pid,
Output {
status,
stdout: fs::read(stdout).unwrap(),
stderr: fs::read(stderr).unwrap(),
},
)
}
fn assert_test_artifacts_removed(pid: u32) {
let test_prefix = format!("dever-application-test-{pid}-");
let build_prefix = format!("dever-build-{pid}-");
let leftovers = fs::read_dir(std::env::temp_dir())
.unwrap()
.filter_map(Result::ok)
.map(|entry| entry.file_name().to_string_lossy().into_owned())
.filter(|name| name.starts_with(&test_prefix) || name.starts_with(&build_prefix))
.collect::<Vec<_>>();
assert!(
leftovers.is_empty(),
"temporary test artifacts remain: {leftovers:?}"
);
}
fn assert_success(output: &Output) {
assert!(
output.status.success(),
"stdout:\n{}\nstderr:\n{}",
String::from_utf8_lossy(&output.stdout),
String::from_utf8_lossy(&output.stderr)
);
}
#[cfg(unix)]
#[test]
fn clean_removes_only_stale_owned_dever_artifacts() {
use std::os::unix::fs::{MetadataExt, symlink};
use std::time::{SystemTime, UNIX_EPOCH};
let project = TemporaryProject::new();
let pid = u64::from(std::process::id()) + 1_000_000;
let suffix = NEXT_DIRECTORY.fetch_add(1, Ordering::Relaxed);
let stale = std::env::temp_dir().join(format!("dever-build-{pid}-{suffix}"));
fs::create_dir(&stale).unwrap();
let owner = fs::metadata(&stale).unwrap().uid();
fs::write(
stale.join(".dever-owner"),
format!(
"dever-build-owner-v1\ncreated=1\npid={pid}\nowner={owner}\ncompiler={}\n",
env!("CARGO_PKG_VERSION"),
),
)
.unwrap();
fs::write(stale.join("program"), b"stale").unwrap();
let fresh_pid = pid + 1;
let fresh = std::env::temp_dir().join(format!("dever-build-{fresh_pid}-{suffix}"));
fs::create_dir(&fresh).unwrap();
let created = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_secs();
fs::write(
fresh.join(".dever-owner"),
format!(
"dever-build-owner-v1\ncreated={created}\npid={fresh_pid}\nowner={owner}\ncompiler={}\n",
env!("CARGO_PKG_VERSION"),
),
).unwrap();
let unknown = std::env::temp_dir().join(format!("dever-build-{}-{suffix}", pid + 2));
fs::create_dir(&unknown).unwrap();
let link = std::env::temp_dir().join(format!("dever-build-{}-{suffix}", pid + 3));
symlink(&unknown, &link).unwrap();
let mut active_process = Command::new("/bin/sleep").arg("60").spawn().unwrap();
let active_pid = u64::from(active_process.id());
let active = std::env::temp_dir().join(format!("dever-build-{active_pid}-{suffix}"));
fs::create_dir(&active).unwrap();
fs::write(
active.join(".dever-owner"),
format!(
"dever-build-owner-v1\ncreated=1\npid={active_pid}\nowner={owner}\ncompiler={}\n",
env!("CARGO_PKG_VERSION"),
),
)
.unwrap();
fs::write(active.join("program"), b"active").unwrap();
let legacy = project.path().join(format!(".dever-run-{pid}"));
fs::write(&legacy, b"stale legacy").unwrap();
let legacy_file = fs::OpenOptions::new().write(true).open(&legacy).unwrap();
legacy_file
.set_times(
fs::FileTimes::new().set_modified(UNIX_EPOCH + std::time::Duration::from_secs(1)),
)
.unwrap();
let fresh_legacy = project.path().join(format!(".dever-run-{}", pid + 1));
fs::write(&fresh_legacy, b"fresh legacy").unwrap();
let active_legacy = project.path().join(format!(".dever-run-{active_pid}"));
fs::write(&active_legacy, b"active legacy").unwrap();
let active_legacy_file = fs::OpenOptions::new()
.write(true)
.open(&active_legacy)
.unwrap();
active_legacy_file
.set_times(
fs::FileTimes::new().set_modified(UNIX_EPOCH + std::time::Duration::from_secs(1)),
)
.unwrap();
let explicit = project.path().join("application");
fs::write(&explicit, b"explicit output").unwrap();
let output = dever(project.path(), "clean", &[]);
active_process.kill().unwrap();
active_process.wait().unwrap();
assert_success(&output);
assert!(
String::from_utf8_lossy(&output.stdout).starts_with("cleaned 1 directories, 3 files, ")
);
assert!(!stale.exists());
assert!(fresh.exists());
assert!(unknown.exists());
assert!(link.symlink_metadata().is_ok());
assert!(active.exists());
assert!(!legacy.exists());
assert!(fresh_legacy.exists());
assert!(active_legacy.exists());
assert!(explicit.exists());
fs::remove_dir_all(fresh).unwrap();
fs::remove_file(link).unwrap();
fs::remove_dir_all(unknown).unwrap();
fs::remove_dir_all(active).unwrap();
}
#[test]
fn cms_project_checks_runs_and_builds_from_an_isolated_copy() {
let workspace = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
for format in ["dever", "md"] {
let project = TemporaryProject::copy_from(&workspace.join("examples/cms").join(format));
let settings_path = project.path().join("config/setting.json");
let production_settings = fs::read(&settings_path).unwrap();
project.block_deployment_database();
for _ in 0..2 {
let (pid, output) = dever_with_pid(project.path(), "test", &[]);
assert_cms_tests(&output);
assert_test_artifacts_removed(pid);
}
fs::write(&settings_path, production_settings).unwrap();
fs::write(project.path().join("test/ignored.dever"), "not valid Dever").unwrap();
assert_success(&dever(project.path(), "check", &[]));
for _ in 0..2 {
assert_health_stdout(&dever(
project.path(),
"run",
&["--", "system.health.ping", "{}"],
));
}
let executable = build(project.path(), "cms-app");
let package = TemporaryProject::package(project.path(), &executable);
assert!(!package.path().join("module").exists());
for _ in 0..2 {
let output = output_with_pid(
Command::new(package.path().join("cms-app"))
.args(["system.health.ping", "{}"])
.current_dir(package.path()),
)
.1;
assert_health_stdout(&output);
}
assert!(fs::read_dir(project.path()).unwrap().all(|entry| {
!entry
.unwrap()
.file_name()
.to_string_lossy()
.starts_with(".dever-run-")
}));
}
}
#[test]
fn project_without_tests_reports_zero_and_succeeds() {
let project = TemporaryProject::new();
fs::create_dir(project.path().join("module")).unwrap();
fs::write(project.path().join("module/main.dever"), "main() () {}").unwrap();
let (pid, output) = dever_with_pid(project.path(), "test", &[]);
assert_success(&output);
assert_eq!(
String::from_utf8_lossy(&output.stdout),
"running 0 tests\n\ntest result: ok. 0 passed; 0 failed; 0 not run\n"
);
assert_test_artifacts_removed(pid);
}
#[test]
fn mixed_suite_initializes_database_only_for_database_cases() {
let workspace = Path::new(env!("CARGO_MANIFEST_DIR")).join("../..");
let project = TemporaryProject::copy_from(&workspace.join("examples/cms/dever"));
project.block_deployment_database();
let health = project.path().join("test/system/health");
fs::create_dir_all(&health).unwrap();
fs::write(
health.join("ping.dever"),
"ping() () { assert_eq(\"ready\", \"ready\") }\n",
)
.unwrap();
let (pid, output) = dever_with_pid(project.path(), "test", &[]);
assert_success(&output);
assert_eq!(
String::from_utf8_lossy(&output.stdout),
"running 6 tests\ntest content/category/lifecycle ... ok\ntest news/article/publish ... ok\ntest system/health/ping ... ok\ntest user/account/bootstrap ... ok\ntest user/account/validation ... ok\ntest user/session/lifecycle ... ok\n\ntest result: ok. 6 passed; 0 failed; 0 not run\n"
);
assert_test_artifacts_removed(pid);
}
#[test]
fn failed_test_reports_captured_output_and_does_not_stop_later_tests() {
let project = TemporaryProject::new();
fs::create_dir(project.path().join("module")).unwrap();
fs::create_dir_all(project.path().join("test/sample/case")).unwrap();
fs::write(project.path().join("module/main.dever"), "main() () {}").unwrap();
fs::write(
project.path().join("test/sample/case/fails.dever"),
r#"fails() () {
blocking(dever.io.println("failed output"))
assert_eq(1, 2)
}
"#,
)
.unwrap();
fs::write(
project.path().join("test/sample/case/passes.dever"),
r#"passes() () {
blocking(dever.io.println("hidden successful output"))
assert(true)
}
"#,
)
.unwrap();
let (pid, output) = dever_with_pid(project.path(), "test", &[]);
assert!(!output.status.success());
assert!(output.stderr.is_empty());
let stdout = String::from_utf8_lossy(&output.stdout);
let failed = stdout.find("test sample/case/fails ... FAILED").unwrap();
let passed = stdout.find("test sample/case/passes ... ok").unwrap();
assert!(failed < passed, "{stdout}");
assert!(
stdout.contains("---- stdout ----\nfailed output\n"),
"{stdout}"
);
assert!(stdout.contains("---- stderr ----"), "{stdout}");
assert!(
stdout.contains("assert_eq failed: actual = 1, expected = 2"),
"{stdout}"
);
assert!(!stdout.contains("hidden successful output"), "{stdout}");
assert!(
stdout.ends_with("test result: FAILED. 1 passed; 1 failed; 0 not run\n"),
"{stdout}"
);
assert_test_artifacts_removed(pid);
}
#[cfg(all(target_os = "linux", target_arch = "x86_64"))]
#[test]
fn suite_compilation_failure_marks_every_discovered_case_failed() {
let project = TemporaryProject::new();
fs::create_dir(project.path().join("module")).unwrap();
fs::create_dir_all(project.path().join("test/sample/case")).unwrap();
fs::write(project.path().join("module/main.dever"), "main() () {}").unwrap();
fs::write(
project.path().join("test/sample/case/first.dever"),
"first() () { assert(true) }\n",
)
.unwrap();
fs::write(
project.path().join("test/sample/case/second.dever"),
"second() () { assert(true) }\n",
)
.unwrap();
let toolchain = TemporaryProject::new();
let compiler = llvm_pack::compiler(
Path::new(env!("CARGO_BIN_EXE_dever")),
toolchain.path(),
"dever",
);
let (pid, output) = output_with_pid(Command::new(compiler).arg("test").arg(project.path()));
assert!(!output.status.success());
assert!(output.stderr.is_empty());
let stdout = String::from_utf8_lossy(&output.stdout);
assert!(
stdout.contains("test sample/case/first ... FAILED"),
"{stdout}"
);
assert!(
stdout.contains("test sample/case/second ... FAILED"),
"{stdout}"
);
assert_eq!(
stdout.matches("cannot inspect runtime pack").count(),
2,
"{stdout}"
);
assert!(
stdout.ends_with("test result: FAILED. 0 passed; 2 failed; 0 not run\n"),
"{stdout}"
);
assert_test_artifacts_removed(pid);
assert!(!toolchain.path().join("cache").exists());
}
fn build(project: &Path, name: &str) -> PathBuf {
let executable = project.join(name);
let build = dever(
project,
"build",
&["--output", executable.to_str().unwrap()],
);
assert_success(&build);
assert!(executable.is_file());
executable
}
fn assert_health_stdout(output: &Output) {
assert_success(output);
let body: serde_json::Value = serde_json::from_slice(&output.stdout).unwrap();
assert_eq!(body["code"], 0);
assert_eq!(body["message"], "ok");
assert_eq!(body["data"]["status"], "ready");
}
fn assert_cms_tests(output: &Output) {
assert_success(output);
assert_eq!(
String::from_utf8_lossy(&output.stdout),
"running 5 tests\ntest content/category/lifecycle ... ok\ntest news/article/publish ... ok\ntest user/account/bootstrap ... ok\ntest user/account/validation ... ok\ntest user/session/lifecycle ... ok\n\ntest result: ok. 5 passed; 0 failed; 0 not run\n"
);
}