mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-10-07 03:00:29 +00:00
use dense run settings in manifest and workflow loaders
This commit is contained in:
parent
3cc094316b
commit
4ce91cdc64
2 changed files with 73 additions and 37 deletions
|
|
@ -8,15 +8,15 @@ use std::path::{Component, Path, PathBuf};
|
|||
|
||||
use anyhow::{Context, Result, anyhow};
|
||||
use fabro_api::types;
|
||||
use fabro_config::parse_settings_layer;
|
||||
use fabro_config::project::{self, discover_project_config, resolve_workflow_path};
|
||||
use fabro_config::run::resolve_run_goal;
|
||||
use fabro_config::run::{resolve_run_goal, resolve_run_goal_from_namespace};
|
||||
use fabro_config::{WorkflowSettingsBuilder, parse_settings_layer};
|
||||
use fabro_graphviz::graph::AttrValue;
|
||||
use fabro_graphviz::parser;
|
||||
use fabro_sandbox::daytona::detect_repo_info;
|
||||
use fabro_types::RunId;
|
||||
use fabro_types::settings::SettingsLayer;
|
||||
use fabro_types::settings::run::{DaytonaDockerfileLayer, ResolvedGoalSource, ResolvedRunGoal};
|
||||
use fabro_types::settings::{Combine, SettingsLayer};
|
||||
use fabro_types::{RunId, WorkflowSettings};
|
||||
use fabro_workflow::git::{GitSyncStatus, head_sha, sync_status};
|
||||
|
||||
use crate::args::{PreflightArgs, RunArgs};
|
||||
|
|
@ -70,21 +70,18 @@ pub(crate) fn build_run_manifest(input: ManifestBuildInput) -> Result<BuiltManif
|
|||
.parent()
|
||||
.unwrap_or_else(|| Path::new("."));
|
||||
let project_config = discover_project_config(workflow_parent)?;
|
||||
let workflow_layer = root_resolution
|
||||
.workflow_config
|
||||
.clone()
|
||||
.unwrap_or_default()
|
||||
.combine(
|
||||
project_config
|
||||
.as_ref()
|
||||
.map(|(_, config)| config.clone())
|
||||
.unwrap_or_default(),
|
||||
);
|
||||
let merged_settings = input
|
||||
.args_layer
|
||||
.clone()
|
||||
.combine(workflow_layer)
|
||||
.combine(input.user_layer);
|
||||
let workflow_layer = root_resolution.workflow_config.clone().unwrap_or_default();
|
||||
let project_layer = project_config
|
||||
.as_ref()
|
||||
.map(|(_, config)| config.clone())
|
||||
.unwrap_or_default();
|
||||
let workflow_settings = WorkflowSettingsBuilder::new()
|
||||
.args_layer(input.args_layer.clone())
|
||||
.workflow_layer(workflow_layer.clone())
|
||||
.project_layer(project_layer)
|
||||
.user_layer(input.user_layer.clone())
|
||||
.build()
|
||||
.map_err(|errors| anyhow!("failed to resolve manifest settings: {errors}"))?;
|
||||
let target_path = root_resolution.dot_path.clone();
|
||||
let target_logical_path = to_logical_path(&target_path, &input.cwd)?;
|
||||
let target_logical_path_string = logical_path_string(&target_logical_path);
|
||||
|
|
@ -124,7 +121,7 @@ pub(crate) fn build_run_manifest(input: ManifestBuildInput) -> Result<BuiltManif
|
|||
|
||||
let goal = resolve_manifest_goal(
|
||||
&input.args_layer,
|
||||
&merged_settings,
|
||||
&workflow_settings,
|
||||
&root_source,
|
||||
&target_path,
|
||||
&input.cwd,
|
||||
|
|
@ -405,12 +402,12 @@ fn collect_bundled_file(
|
|||
|
||||
fn resolve_manifest_goal(
|
||||
args_layer: &SettingsLayer,
|
||||
settings: &SettingsLayer,
|
||||
settings: &WorkflowSettings,
|
||||
root_source: &str,
|
||||
root_dot_path: &Path,
|
||||
cwd: &Path,
|
||||
) -> Result<Option<types::ManifestGoal>> {
|
||||
let working_directory = project::resolve_working_directory(settings, cwd);
|
||||
let working_directory = project::resolve_working_directory_from_run(&settings.run, cwd);
|
||||
|
||||
// Precedence 1: CLI args (`--goal` / `--goal-file`). These are already
|
||||
// resolved to absolute paths by `overrides::goal_layer_from_args`.
|
||||
|
|
@ -423,7 +420,7 @@ fn resolve_manifest_goal(
|
|||
// Precedence 2: merged config `run.goal`. Config-sourced `goal.file`
|
||||
// paths were rewritten to absolute by `load_settings_path` at the
|
||||
// directory of the config file that declared them.
|
||||
if let Some(resolved) = resolve_run_goal(settings, &working_directory)
|
||||
if let Some(resolved) = resolve_run_goal_from_namespace(&settings.run, &working_directory)
|
||||
.context("failed to resolve run.goal.file contents")?
|
||||
{
|
||||
return Ok(Some(resolved_goal_to_manifest(resolved)));
|
||||
|
|
|
|||
|
|
@ -6,10 +6,11 @@
|
|||
use std::path::{Path, PathBuf};
|
||||
use std::sync::Arc;
|
||||
|
||||
use anyhow::Context;
|
||||
use fabro_config::project as project_config;
|
||||
use fabro_config::run::resolve_run_goal;
|
||||
use anyhow::{Context, anyhow};
|
||||
use fabro_config::run::resolve_run_goal_from_namespace;
|
||||
use fabro_config::{WorkflowSettingsBuilder, project as project_config};
|
||||
use fabro_types::settings::SettingsLayer;
|
||||
use fabro_types::settings::run::RunNamespace;
|
||||
|
||||
use crate::file_resolver::{FileResolver, FilesystemFileResolver};
|
||||
use crate::workflow_bundle::BundledWorkflow;
|
||||
|
|
@ -67,11 +68,10 @@ pub(crate) fn resolve_workflow(request: ResolveWorkflowInput) -> anyhow::Result<
|
|||
WorkflowInput::Path(workflow_path) => {
|
||||
let resolution = project_config::resolve_workflow_path(&workflow_path, &request.cwd)?;
|
||||
let settings = request.settings;
|
||||
let working_directory =
|
||||
project_config::resolve_working_directory(&settings, &request.cwd);
|
||||
let raw_source = std::fs::read_to_string(&resolution.dot_path)
|
||||
.with_context(|| format!("Failed to read {}", resolution.dot_path.display()))?;
|
||||
let goal_override = resolve_goal_override(&settings, &working_directory)?;
|
||||
let (_run_settings, working_directory, goal_override) =
|
||||
resolve_runtime_run_settings(&settings, &request.cwd)?;
|
||||
let current_dir = resolution
|
||||
.dot_path
|
||||
.parent()
|
||||
|
|
@ -94,9 +94,8 @@ pub(crate) fn resolve_workflow(request: ResolveWorkflowInput) -> anyhow::Result<
|
|||
}
|
||||
WorkflowInput::DotSource { source, base_dir } => {
|
||||
let settings = request.settings;
|
||||
let working_directory =
|
||||
project_config::resolve_working_directory(&settings, &request.cwd);
|
||||
let goal_override = resolve_goal_override(&settings, &working_directory)?;
|
||||
let (_run_settings, working_directory, goal_override) =
|
||||
resolve_runtime_run_settings(&settings, &request.cwd)?;
|
||||
let has_base_dir = base_dir.is_some();
|
||||
Ok(ResolvedWorkflow {
|
||||
raw_source: source,
|
||||
|
|
@ -116,9 +115,8 @@ pub(crate) fn resolve_workflow(request: ResolveWorkflowInput) -> anyhow::Result<
|
|||
}
|
||||
WorkflowInput::Bundled(workflow) => {
|
||||
let settings = request.settings;
|
||||
let working_directory =
|
||||
project_config::resolve_working_directory(&settings, &request.cwd);
|
||||
let goal_override = resolve_goal_override(&settings, &working_directory)?;
|
||||
let (_run_settings, working_directory, goal_override) =
|
||||
resolve_runtime_run_settings(&settings, &request.cwd)?;
|
||||
|
||||
Ok(ResolvedWorkflow {
|
||||
raw_source: workflow.source.clone(),
|
||||
|
|
@ -135,15 +133,27 @@ pub(crate) fn resolve_workflow(request: ResolveWorkflowInput) -> anyhow::Result<
|
|||
}
|
||||
}
|
||||
|
||||
fn resolve_runtime_run_settings(
|
||||
settings: &SettingsLayer,
|
||||
cwd: &Path,
|
||||
) -> anyhow::Result<(RunNamespace, PathBuf, Option<String>)> {
|
||||
let run_settings = WorkflowSettingsBuilder::from_layer(settings)
|
||||
.map_err(|errors| anyhow!("failed to resolve workflow settings: {errors}"))?
|
||||
.run;
|
||||
let working_directory = project_config::resolve_working_directory_from_run(&run_settings, cwd);
|
||||
let goal_override = resolve_goal_override(&run_settings, &working_directory)?;
|
||||
Ok((run_settings, working_directory, goal_override))
|
||||
}
|
||||
|
||||
/// Resolve the `run.goal` override for a direct (non-manifest) workflow
|
||||
/// run. Reads the file from disk if the goal layer is the `file` variant.
|
||||
/// Relative paths that survived config load (e.g. env-interpolated ones)
|
||||
/// are anchored at `working_directory`.
|
||||
fn resolve_goal_override(
|
||||
settings: &SettingsLayer,
|
||||
run_settings: &RunNamespace,
|
||||
working_directory: &Path,
|
||||
) -> anyhow::Result<Option<String>> {
|
||||
resolve_run_goal(settings, working_directory)
|
||||
resolve_run_goal_from_namespace(run_settings, working_directory)
|
||||
.map(|opt| opt.map(|resolved| resolved.text))
|
||||
.map_err(anyhow::Error::from)
|
||||
}
|
||||
|
|
@ -176,4 +186,33 @@ mod tests {
|
|||
|
||||
assert_eq!(resolved.working_directory, dir.path().join("workspace"));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn resolve_workflow_reads_goal_override_from_dense_run_settings() {
|
||||
use fabro_types::settings::InterpString;
|
||||
use fabro_types::settings::run::{RunGoalLayer, RunLayer};
|
||||
|
||||
let dir = tempfile::tempdir().unwrap();
|
||||
let goal_path = dir.path().join("goal.md");
|
||||
std::fs::write(&goal_path, "dense goal").unwrap();
|
||||
let resolved = resolve_workflow(ResolveWorkflowInput {
|
||||
workflow: WorkflowInput::DotSource {
|
||||
source: "digraph Test { start -> exit }".to_string(),
|
||||
base_dir: None,
|
||||
},
|
||||
settings: SettingsLayer {
|
||||
run: Some(RunLayer {
|
||||
goal: Some(RunGoalLayer::File {
|
||||
file: InterpString::parse(&goal_path.display().to_string()),
|
||||
}),
|
||||
..RunLayer::default()
|
||||
}),
|
||||
..SettingsLayer::default()
|
||||
},
|
||||
cwd: dir.path().to_path_buf(),
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(resolved.goal_override.as_deref(), Some("dense goal"));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue