Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -40,4 +40,4 @@ jobs:
cargo-${{ runner.os }}-

- name: Run CI Pipeline
run: cargo run -p gunbc-ci --release
run: cargo run -p gunbc-dag --bin gunbc-ci --release
2 changes: 1 addition & 1 deletion .gitlab-ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,4 @@ cache:
ci:
stage: ci
script:
- cargo run -p gunbc-ci --release
- cargo run -p gunbc-dag --bin gunbc-ci --release
52 changes: 41 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
# Generated by gunbc-makegen
# DO NOT EDIT - regenerate with: make makegen

# Naming convention:
# make <target> - verify only (CI-safe, fails on issues)
# make <target>-fix - auto-fix then verify (for dev)
#
# Dev workflow: make test-fix (fix everything, then test)
# CI verification: make test (verify fmt + lint + test)

.DEFAULT_GOAL := help

.PHONY: help codegen ensure-codegen build clean test check clippy fmt fmt-check ci-yaml gist gist-dry buck2 buck2-dry makegen makegen-dry deps deps-dry ci ci-dry bootstrap bootstrap-dry dag-viz
.PHONY: help codegen ensure-codegen build clean fmt-fix lint-fix test test-fix check check-fix clippy clippy-fix fmt fmt-check ci-yaml gist gist-dry buck2 buck2-dry makegen makegen-dry deps deps-dry ci ci-dry bootstrap bootstrap-dry

# Ensure codegen has run (upsert pattern: check stamp -> run if missing)
ensure-codegen:
Expand All @@ -26,15 +33,22 @@ clean:
help:
@echo "gunbc tools - generated Makefile"
@echo ""
@echo "Naming convention:"
@echo " make <target> - verify only (CI-safe)"
@echo " make <target>-fix - auto-fix then verify (for dev)"
@echo ""
@echo "Build transactions:"
@echo " build - Commit: codegen → cargo build"
@echo " clean - Rollback: remove all generated artifacts"
@echo " codegen - Partial commit: just generate CLIs"
@echo ""
@echo "Development:"
@echo " test - Run all tests"
@echo " test-fix - Run all tests (fmt-fix + lint-fix first)"
@echo " check - Type check all targets"
@echo " check-fix - Type check all targets (fmt-fix first)"
@echo " clippy - Run clippy linter"
@echo " clippy-fix - Run clippy linter (auto-fix)"
@echo " fmt - Format all code"
@echo " fmt-check - Format all code (check only)"
@echo " ci-yaml - Generate CI workflow YAML (GitHub Actions & GitLab CI)"
Expand All @@ -53,18 +67,38 @@ help:
# Meta Targets - Development workflow commands
# ============================================================================

# fmt-fix: apply formatting (alias for fmt)
fmt-fix:
@cargo fmt

# lint-fix: auto-fix lint issues where possible
lint-fix: ensure-codegen
@cargo clippy --fix --workspace --allow-dirty --allow-staged -- -D warnings

# test: Run all tests
test: build
@cargo test

# test-fix: auto-fix then verify
test-fix: fmt-fix lint-fix build
@cargo test

# check: Type check all targets
check: ensure-codegen
@cargo check --all-targets

# check-fix: auto-fix then verify
check-fix: fmt-fix ensure-codegen
@cargo check --all-targets

# clippy: Run clippy linter
clippy: ensure-codegen
@cargo clippy --all-targets -- -D warnings

# clippy-fix: auto-fix then verify
clippy-fix: ensure-codegen
@cargo clippy --fix --workspace --allow-dirty --allow-staged -- -D warnings

# fmt: Format all code
fmt:
@cargo fmt
Expand Down Expand Up @@ -92,10 +126,10 @@ buck2-dry: ensure-codegen

# gunbc-makegen entrypoints: output_path (String)
makegen: ensure-codegen
@cargo run -p gunbc-makegen -- $(if $(OUTPUT),--output $(OUTPUT))
@cargo run -p gunbc-dag --bin gunbc-makegen -- $(if $(OUTPUT),--output $(OUTPUT))

makegen-dry: ensure-codegen
@cargo run -p gunbc-makegen -- --dry-run $(if $(OUTPUT),--output $(OUTPUT))
@cargo run -p gunbc-dag --bin gunbc-makegen -- --dry-run $(if $(OUTPUT),--output $(OUTPUT))

# gunbc-deps entrypoints: manifest_path (String)
deps: ensure-codegen
Expand All @@ -106,19 +140,15 @@ deps-dry: ensure-codegen

# gunbc-ci entrypoints:
ci: ensure-codegen
@cargo run -p gunbc-ci --
@cargo run -p gunbc-dag --bin gunbc-ci --

ci-dry: ensure-codegen
@cargo run -p gunbc-ci -- --dry-run
@cargo run -p gunbc-dag --bin gunbc-ci -- --dry-run

# gunbc-bootstrap entrypoints:
bootstrap: ensure-codegen
@cargo run -p gunbc-bootstrap --
@cargo run -p gunbc-dag --bin gunbc-bootstrap --

bootstrap-dry: ensure-codegen
@cargo run -p gunbc-bootstrap -- --dry-run

# dag-viz: Generate interactive DAG visualization (opens in browser)
dag-viz:
@cargo run -p gunbc-dag --bin gunbc-dag-viz
@cargo run -p gunbc-dag --bin gunbc-bootstrap -- --dry-run

25 changes: 15 additions & 10 deletions core/codegen/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -285,7 +285,13 @@ fn cmd_cigen(dry_run: bool) {

// Generate CI YAML for gunbc-ci
// gunbc-ci is special - it has a handwritten main.rs that handles codegen internally
let config = RenderConfig::new("ci", "gunbc-ci")
let codegen = gunbc_ir::CargoInvocation::standalone("codegen");
let tool = gunbc_ir::CargoInvocation::composed("ci", "dag");
let config = RenderConfig::new("ci", tool)
.with_generator(
&codegen.binary,
&format!("{} -- cigen", codegen.command()),
)
.with_runner("ubuntu-latest")
.with_env("CARGO_TERM_COLOR", "always")
.with_branches(vec!["main"]);
Expand Down Expand Up @@ -368,10 +374,9 @@ fn cmd_clippy_toml(dry_run: bool) {
/// Generate GitHub Actions YAML template.
fn generate_github_actions_template(config: &RenderConfig) -> String {
let mut yaml = String::new();

yaml.push_str("# Generated by gunbc-codegen cigen. Do not edit manually.\n");
yaml.push_str("# Regenerate with: cargo run -p gunbc-codegen -- cigen\n\n");
yaml.push_str(&format!("name: {}\n\n", config.workflow_name));

yaml.push_str(&config.header("#"));
yaml.push_str(&format!("\n\nname: {}\n\n", config.workflow_name));

// Triggers
yaml.push_str("on:\n");
Expand Down Expand Up @@ -433,17 +438,17 @@ fn generate_github_actions_template(config: &RenderConfig) -> String {
// The prep node uses the resource acquisition (upsert) pattern: check if generated
// files exist, generate them if not. This makes CI self-healing.
yaml.push_str(" - name: Run CI Pipeline\n");
yaml.push_str(&format!(" run: cargo run -p {} --release\n", config.tool_binary));
yaml.push_str(&format!(" run: {} --release\n", config.tool.command()));

yaml
}

/// Generate GitLab CI YAML template.
fn generate_gitlab_ci_template(config: &RenderConfig) -> String {
let mut yaml = String::new();
yaml.push_str("# Generated by gunbc-codegen cigen. Do not edit manually.\n");
yaml.push_str("# Regenerate with: cargo run -p gunbc-codegen -- cigen\n\n");

yaml.push_str(&config.header("#"));
yaml.push_str("\n\n");

// Image
yaml.push_str("image: rust:latest\n\n");
Expand Down Expand Up @@ -473,7 +478,7 @@ fn generate_gitlab_ci_template(config: &RenderConfig) -> String {
yaml.push_str(&format!("{}:\n", config.workflow_name));
yaml.push_str(" stage: ci\n");
yaml.push_str(" script:\n");
yaml.push_str(&format!(" - cargo run -p {} --release\n", config.tool_binary));
yaml.push_str(&format!(" - {} --release\n", config.tool.command()));

yaml
}
Expand Down
11 changes: 6 additions & 5 deletions core/codegen/src/registry.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
//! Eventually, the entire graph.rs can be generated from these definitions.

use crate::cli_gen::{CliBoundary, CliEntrypoint, ToolMeta};
use gunbc_ir::cargo;

// ============================================================================
// DAG Definition Structures
Expand Down Expand Up @@ -288,7 +289,7 @@ pub fn all_tools() -> Vec<ToolDef> {
vec![
// gunbc-gist (uses DagBuilder - returns Result)
ToolDef::new(
"gunbc-gist",
&cargo::name("gist"),
"gist",
"Create a GitHub gist from code files",
"build_gist_graph",
Expand Down Expand Up @@ -321,7 +322,7 @@ pub fn all_tools() -> Vec<ToolDef> {

// gunbc-buck2 (uses DagBuilder - returns Result)
ToolDef::new(
"gunbc-buck2",
&cargo::name("buck2"),
"buck2",
"Generate BUCK file from Cargo.toml",
"build_buck2_graph",
Expand Down Expand Up @@ -352,7 +353,7 @@ pub fn all_tools() -> Vec<ToolDef> {

// gunbc-makegen (uses DagBuilder - returns Result)
ToolDef::new(
"gunbc-makegen",
&cargo::name("makegen"),
"makegen",
"Generate Makefile from tool registry",
"build_makegen_graph",
Expand All @@ -379,7 +380,7 @@ pub fn all_tools() -> Vec<ToolDef> {

// gunbc-deps (uses DagBuilder - returns Result)
ToolDef::new(
"gunbc-deps",
&cargo::name("deps"),
"deps",
"Install tool dependencies",
"build_deps_graph",
Expand Down Expand Up @@ -408,7 +409,7 @@ pub fn all_tools() -> Vec<ToolDef> {

// gunbc-bootstrap (uses DagBuilder - returns Result)
ToolDef::new(
"gunbc-bootstrap",
&cargo::name("bootstrap"),
"bootstrap",
"Generate Makefile and .gitignore",
"build_bootstrap_graph",
Expand Down
45 changes: 42 additions & 3 deletions core/exec/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -505,12 +505,19 @@ fn execute_flat<T: Executable>(
};

node_outputs.insert(node_id.0.clone(), outputs.clone());
entries.push(LogEntry {
let entry = LogEntry {
node_id: node_id.0.clone(),
outputs,
was_intercepted,
});

};

// Print node outputs inside the CI group so they appear in the
// collapsible section, not after all groups have closed.
if ci_ctx.is_some() {
print_log_entry(&entry);
}
entries.push(entry);

// End CI group for this node
if let Some(ref mut ci) = ci_ctx {
ci.end_group();
Expand All @@ -520,6 +527,38 @@ fn execute_flat<T: Executable>(
Ok(ExecutionLog { entries })
}

/// Print a log entry's outputs to stdout.
///
/// Used inside CI groups so that node outputs appear within the
/// collapsible section rather than in a flat summary after all groups.
fn print_log_entry(entry: &LogEntry) {
for (port, value) in &entry.outputs {
match value {
Value::Str(s) => {
if port.ends_with("stderr") || port.ends_with("stdout") {
if !s.is_empty() {
println!(" {port}: {s}");
}
} else if s.contains('\n') {
// Multi-line values (reports, etc.) — print in full
println!(" {port}: {s}");
} else if s.len() < 120 {
println!(" {port}: {s}");
} else {
println!(" {port}: {}...", &s[..80]);
}
}
Value::Int(i) => println!(" {port}: {i}"),
Value::Bool(b) => println!(" {port}: {b}"),
Value::StrList(list) => println!(" {port}: [{} items]", list.len()),
Value::MapStrStr(map) => println!(" {port}: {{{} entries}}", map.len()),
Value::Json(_) => println!(" {port}: <JSON>"),
Value::Skipped => {} // Don't print skipped outputs
_ => {}
}
}
}

/// Check whether a node should be skipped based on guard predicates.
fn should_skip_node<T>(node: &Node<T>, inputs: &HashMap<String, Value>) -> bool {
for port in &node.inputs {
Expand Down
Loading