diff --git a/.github/workflows/e2e.yml b/.github/workflows/e2e.yml index 336fe4e3..fd0e1748 100644 --- a/.github/workflows/e2e.yml +++ b/.github/workflows/e2e.yml @@ -110,7 +110,6 @@ jobs: - name: Test pcb import (E2E) run: | - pcb new --workspace test-import --repo github.com/test/test-import find kicad-test-fixtures -name '*.kicad_pro' | while IFS= read -r pro; do echo "=== Importing $pro ===" pcb import "$pro" ./test-import diff --git a/CHANGELOG.md b/CHANGELOG.md index 44d7bacd..bd502f1d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ and this project adheres to Semantic Versioning (https://semver.org/spec/v2.0.0. ## [Unreleased] +### Changed + +- `pcb import` now scaffolds a full workspace (git init, README, .gitignore) when the output directory is new, matching `pcb new --workspace`. + ## [0.3.39] - 2026-02-11 ### Fixed diff --git a/crates/pcb/src/import/paths.rs b/crates/pcb/src/import/paths.rs index 8a7914c8..0cf0a57a 100644 --- a/crates/pcb/src/import/paths.rs +++ b/crates/pcb/src/import/paths.rs @@ -32,7 +32,8 @@ fn ensure_workspace_root(path: &Path) -> Result { if path.exists() && !path.is_dir() { anyhow::bail!("Output directory is not a directory: {}", path.display()); } - if !path.exists() { + let created = !path.exists(); + if created { fs::create_dir_all(path) .with_context(|| format!("Failed to create output directory: {}", path.display()))?; } @@ -49,12 +50,6 @@ fn ensure_workspace_root(path: &Path) -> Result { pcb_toml.display() ); } - if !config.is_v2() { - anyhow::bail!( - "Output directory contains a legacy (V1) workspace pcb.toml; run `pcb migrate`: {}", - pcb_toml.display() - ); - } return Ok(workspace_root); } @@ -74,23 +69,11 @@ fn ensure_workspace_root(path: &Path) -> Result { ); } - write_minimal_workspace_pcb_toml(&pcb_toml)?; + if let Err(e) = crate::new::init_workspace(&workspace_root, "") { + if created { + let _ = fs::remove_dir_all(&workspace_root); + } + return Err(e); + } Ok(workspace_root) } - -fn write_minimal_workspace_pcb_toml(path: &Path) -> Result<()> { - use pcb_zen_core::config::{default_members, PcbToml, WorkspaceConfig}; - - let config = PcbToml { - workspace: Some(WorkspaceConfig { - pcb_version: Some(crate::migrate::codemods::manifest_v2::pcb_version_from_cargo()), - members: default_members(), - ..WorkspaceConfig::default() - }), - ..PcbToml::default() - }; - - let content = toml::to_string_pretty(&config)?; - fs::write(path, content).with_context(|| format!("Failed to write {}", path.display()))?; - Ok(()) -} diff --git a/crates/pcb/src/new.rs b/crates/pcb/src/new.rs index 19936cd5..7f1a4d13 100644 --- a/crates/pcb/src/new.rs +++ b/crates/pcb/src/new.rs @@ -231,36 +231,20 @@ fn prompt_new_package() -> Result<()> { execute_new_package(&path) } -fn execute_new_workspace(workspace: &str, repo: Option<&str>) -> Result<()> { - if get_workspace().is_some() { - bail!("Cannot create a workspace inside an existing workspace"); - } - - validate_name(workspace, "Workspace")?; - - let repo = - repo.ok_or_else(|| anyhow::anyhow!("--repo is required when creating a workspace"))?; - let repository = clean_repo_url(repo)?; - - let workspace_path = Path::new(workspace); - - if workspace_path.exists() { - bail!("Directory '{}' already exists", workspace); - } - - std::fs::create_dir_all(workspace_path) - .with_context(|| format!("Failed to create directory '{}'", workspace))?; - - let status = Command::new("git") - .args(["init", "-b", "main"]) - .current_dir(workspace_path) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .status() - .context("Failed to run 'git init'")?; - - if !status.success() { - bail!("'git init' failed with exit code: {:?}", status.code()); +/// Initialize workspace scaffolding in an existing directory: pcb.toml, README, +/// .gitignore, git init, and skill path. `repository` may be empty. +pub(crate) fn init_workspace(dir: &Path, repository: &str) -> Result<()> { + if !dir.join(".git").exists() { + let status = Command::new("git") + .args(["init", "-b", "main"]) + .current_dir(dir) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .status() + .context("Failed to run 'git init'")?; + if !status.success() { + bail!("'git init' failed with exit code: {:?}", status.code()); + } } let env = create_template_env(); @@ -274,21 +258,44 @@ fn execute_new_workspace(workspace: &str, repo: Option<&str>) -> Result<()> { .unwrap() .render(&ctx) .context("Failed to render pcb.toml template")?; - std::fs::write(workspace_path.join("pcb.toml"), pcb_toml_content) - .context("Failed to write pcb.toml")?; + std::fs::write(dir.join("pcb.toml"), pcb_toml_content).context("Failed to write pcb.toml")?; let readme_content = env .get_template("workspace_readme") .unwrap() .render(&ctx) .context("Failed to render README.md template")?; - std::fs::write(workspace_path.join("README.md"), readme_content) - .context("Failed to write README.md")?; + std::fs::write(dir.join("README.md"), readme_content).context("Failed to write README.md")?; - std::fs::write(workspace_path.join(".gitignore"), GITIGNORE_TEMPLATE) + std::fs::write(dir.join(".gitignore"), GITIGNORE_TEMPLATE) .context("Failed to write .gitignore")?; - add_skill_to_path(workspace_path)?; + add_skill_to_path(dir)?; + + Ok(()) +} + +fn execute_new_workspace(workspace: &str, repo: Option<&str>) -> Result<()> { + if get_workspace().is_some() { + bail!("Cannot create a workspace inside an existing workspace"); + } + + validate_name(workspace, "Workspace")?; + + let repo = + repo.ok_or_else(|| anyhow::anyhow!("--repo is required when creating a workspace"))?; + let repository = clean_repo_url(repo)?; + + let workspace_path = Path::new(workspace); + + if workspace_path.exists() { + bail!("Directory '{}' already exists", workspace); + } + + std::fs::create_dir_all(workspace_path) + .with_context(|| format!("Failed to create directory '{}'", workspace))?; + + init_workspace(workspace_path, &repository)?; eprintln!( "{} {} ({})", diff --git a/crates/pcb/src/templates/workspace_pcb_toml.jinja b/crates/pcb/src/templates/workspace_pcb_toml.jinja index 12536099..a3804568 100644 --- a/crates/pcb/src/templates/workspace_pcb_toml.jinja +++ b/crates/pcb/src/templates/workspace_pcb_toml.jinja @@ -1,6 +1,6 @@ [workspace] -repository = "{{ repository }}" -pcb-version = "{{ pcb_version }}" +{% if repository %}repository = "{{ repository }}" +{% endif %}pcb-version = "{{ pcb_version }}" members = [ "components/*", "modules/*",