re-uploading work
This commit is contained in:
433
work-summary/sessions/2026-01-18-cli-output-enhancements.md
Normal file
433
work-summary/sessions/2026-01-18-cli-output-enhancements.md
Normal file
@@ -0,0 +1,433 @@
|
||||
# Work Summary: CLI Output Enhancements
|
||||
**Date**: 2026-01-18
|
||||
**Session**: 7 (continued)
|
||||
**Status**: ✅ Complete
|
||||
|
||||
## Overview
|
||||
|
||||
Enhanced the CLI with shorthand output flags for better interoperability with Unix tools, and added a new command to extract raw execution results for piping to other command-line utilities.
|
||||
|
||||
## Objectives
|
||||
|
||||
- Add shorthand flags for JSON (`-j`) and YAML (`-y`) output
|
||||
- Enable easy piping to tools like `jq`, `yq`, etc.
|
||||
- Add command to get raw execution result data
|
||||
- Maintain backward compatibility
|
||||
- Follow Unix command-line conventions
|
||||
|
||||
## Implementation Details
|
||||
|
||||
### 1. Shorthand Output Flags
|
||||
|
||||
#### Added Global Flags (`main.rs`)
|
||||
|
||||
```rust
|
||||
/// Output as JSON (shorthand for --output json)
|
||||
#[arg(short = 'j', long, global = true, conflicts_with_all = ["output", "yaml"])]
|
||||
json: bool,
|
||||
|
||||
/// Output as YAML (shorthand for --output yaml)
|
||||
#[arg(short = 'y', long, global = true, conflicts_with_all = ["output", "json"])]
|
||||
yaml: bool,
|
||||
```
|
||||
|
||||
#### Flag Resolution Logic
|
||||
|
||||
Implemented priority-based resolution:
|
||||
1. `-j/--json` → JSON output
|
||||
2. `-y/--yaml` → YAML output
|
||||
3. `--output <format>` → Specified format
|
||||
4. Default → Table format
|
||||
|
||||
```rust
|
||||
let output_format = if cli.json {
|
||||
output::OutputFormat::Json
|
||||
} else if cli.yaml {
|
||||
output::OutputFormat::Yaml
|
||||
} else {
|
||||
cli.output
|
||||
};
|
||||
```
|
||||
|
||||
#### Conflict Handling
|
||||
|
||||
Flags are mutually exclusive:
|
||||
- `-j` conflicts with `--output` and `-y`
|
||||
- `-y` conflicts with `--output` and `-j`
|
||||
- `--output` conflicts with `-j` and `-y`
|
||||
|
||||
### 2. Raw Execution Result Command
|
||||
|
||||
#### New Subcommand (`commands/execution.rs`)
|
||||
|
||||
Added `attune execution result <id>` command:
|
||||
|
||||
```rust
|
||||
Result {
|
||||
/// Execution ID
|
||||
execution_id: i64,
|
||||
|
||||
/// Output format (json or yaml, default: json)
|
||||
#[arg(short = 'f', long, value_enum, default_value = "json")]
|
||||
format: ResultFormat,
|
||||
}
|
||||
```
|
||||
|
||||
#### Result Format Enum
|
||||
|
||||
```rust
|
||||
#[derive(Debug, Clone, Copy, clap::ValueEnum)]
|
||||
pub enum ResultFormat {
|
||||
Json,
|
||||
Yaml,
|
||||
}
|
||||
```
|
||||
|
||||
#### Implementation
|
||||
|
||||
```rust
|
||||
async fn handle_result(
|
||||
execution_id: i64,
|
||||
format: ResultFormat,
|
||||
api_url: &Option<String>,
|
||||
) -> Result<()> {
|
||||
let config = CliConfig::load()?;
|
||||
let client = ApiClient::from_config(&config, api_url);
|
||||
|
||||
let path = format!("/executions/{}", execution_id);
|
||||
let execution: ExecutionDetail = client.get(&path).await?;
|
||||
|
||||
if let Some(result) = execution.result {
|
||||
match format {
|
||||
ResultFormat::Json => {
|
||||
println!("{}", serde_json::to_string_pretty(&result)?);
|
||||
}
|
||||
ResultFormat::Yaml => {
|
||||
println!("{}", serde_yaml::to_string(&result)?);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
anyhow::bail!("Execution {} has no result yet", execution_id);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
```
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Shorthand Output Flags
|
||||
|
||||
```bash
|
||||
# JSON output (long form)
|
||||
attune pack list --output json
|
||||
|
||||
# JSON output (shorthand)
|
||||
attune pack list -j
|
||||
|
||||
# YAML output (shorthand)
|
||||
attune pack list -y
|
||||
|
||||
# Works with all commands
|
||||
attune execution list -j
|
||||
attune action list -y
|
||||
attune rule show core.my_rule -j
|
||||
```
|
||||
|
||||
### Raw Execution Result
|
||||
|
||||
```bash
|
||||
# Get result as JSON (default)
|
||||
attune execution result 123
|
||||
|
||||
# Get result as YAML
|
||||
attune execution result 123 --format yaml
|
||||
|
||||
# Pipe to jq for field extraction
|
||||
attune execution result 123 | jq '.data.status'
|
||||
|
||||
# Extract specific array elements
|
||||
attune execution result 123 | jq -r '.errors[]'
|
||||
|
||||
# Complex jq filtering
|
||||
attune execution result 123 | jq '.results[] | select(.status == "success")'
|
||||
|
||||
# Pipe to yq
|
||||
attune execution result 123 --format yaml | yq '.data.field'
|
||||
|
||||
# Use in scripts
|
||||
STATUS=$(attune execution result 123 | jq -r '.status')
|
||||
if [ "$STATUS" = "success" ]; then
|
||||
echo "Execution succeeded"
|
||||
fi
|
||||
```
|
||||
|
||||
### Piping to Other Tools
|
||||
|
||||
```bash
|
||||
# Count items in result
|
||||
attune execution result 123 | jq '.items | length'
|
||||
|
||||
# Format and colorize JSON
|
||||
attune execution result 123 | jq -C '.'
|
||||
|
||||
# Convert between formats
|
||||
attune execution result 123 | yq -P
|
||||
|
||||
# Extract to file
|
||||
attune execution result 123 | jq '.data' > result.json
|
||||
|
||||
# Grep in JSON
|
||||
attune execution result 123 | jq -r '.logs[]' | grep ERROR
|
||||
|
||||
# Chain multiple commands
|
||||
attune execution list -j | \
|
||||
jq -r '.[] | select(.status == "failed") | .id' | \
|
||||
xargs -I {} attune execution result {} | \
|
||||
jq -r '.error'
|
||||
```
|
||||
|
||||
## Integration with Unix Tools
|
||||
|
||||
### With jq (JSON processor)
|
||||
|
||||
```bash
|
||||
# Filter executions and extract results
|
||||
attune execution list -j | \
|
||||
jq '.[] | select(.pack_name == "monitoring")' | \
|
||||
jq -r '.id' | \
|
||||
while read id; do
|
||||
attune execution result $id | jq '.metrics'
|
||||
done
|
||||
```
|
||||
|
||||
### With yq (YAML processor)
|
||||
|
||||
```bash
|
||||
# Get pack config as YAML
|
||||
attune pack show core -y | yq '.metadata'
|
||||
```
|
||||
|
||||
### With grep/awk/sed
|
||||
|
||||
```bash
|
||||
# Search in execution results
|
||||
attune execution list --pack core -j | \
|
||||
jq -r '.[] | "\(.id) \(.status)"' | \
|
||||
grep failed | \
|
||||
awk '{print $1}' | \
|
||||
xargs -I {} attune execution result {}
|
||||
```
|
||||
|
||||
### With xargs for batch operations
|
||||
|
||||
```bash
|
||||
# Process all failed executions
|
||||
attune execution list --status failed -j | \
|
||||
jq -r '.[].id' | \
|
||||
xargs -I {} attune execution result {} | \
|
||||
jq -s '.' # Combine all results into single array
|
||||
```
|
||||
|
||||
## Benefits
|
||||
|
||||
### 1. Interoperability
|
||||
- Follows Unix convention for shorthand flags
|
||||
- Easy piping to standard tools (`jq`, `yq`, `grep`, etc.)
|
||||
- Compatible with shell scripting best practices
|
||||
|
||||
### 2. Convenience
|
||||
- Shorter commands: `-j` vs `--output json`
|
||||
- Faster typing for interactive use
|
||||
- Less verbose scripts
|
||||
|
||||
### 3. Data Extraction
|
||||
- Get just the result data without wrapper
|
||||
- No need to parse full execution object
|
||||
- Direct access to execution output
|
||||
|
||||
### 4. Scripting
|
||||
- Easy automation with standard tools
|
||||
- Clean data flow in pipelines
|
||||
- Reduced need for custom parsing
|
||||
|
||||
## Use Cases
|
||||
|
||||
### 1. Monitoring Scripts
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# Check execution results for errors
|
||||
|
||||
for id in $(attune execution list --status succeeded -j | jq -r '.[].id'); do
|
||||
ERROR_COUNT=$(attune execution result $id | jq '.errors | length')
|
||||
if [ "$ERROR_COUNT" -gt 0 ]; then
|
||||
echo "Execution $id has $ERROR_COUNT errors"
|
||||
fi
|
||||
done
|
||||
```
|
||||
|
||||
### 2. Data Aggregation
|
||||
|
||||
```bash
|
||||
# Aggregate metrics from multiple executions
|
||||
attune execution list --pack monitoring -j | \
|
||||
jq -r '.[].id' | \
|
||||
xargs -I {} attune execution result {} | \
|
||||
jq -s 'map(.metrics) | add'
|
||||
```
|
||||
|
||||
### 3. CI/CD Integration
|
||||
|
||||
```bash
|
||||
# Execute action and check result
|
||||
EXEC_ID=$(attune action execute ci.deploy -j | jq -r '.id')
|
||||
attune execution result $EXEC_ID | jq -e '.success' || exit 1
|
||||
```
|
||||
|
||||
### 4. Log Analysis
|
||||
|
||||
```bash
|
||||
# Extract and analyze logs from results
|
||||
attune execution result 123 | \
|
||||
jq -r '.logs[]' | \
|
||||
grep ERROR | \
|
||||
sort | uniq -c
|
||||
```
|
||||
|
||||
## Technical Details
|
||||
|
||||
### Flag Conflicts
|
||||
|
||||
Clap's `conflicts_with_all` ensures mutual exclusivity:
|
||||
- Prevents: `attune pack list -j -y` (error)
|
||||
- Prevents: `attune pack list -j --output table` (error)
|
||||
- Allows: `attune pack list -j` (valid)
|
||||
|
||||
### Error Handling
|
||||
|
||||
Result command provides clear error when execution has no result:
|
||||
```
|
||||
Error: Execution 123 has no result yet
|
||||
```
|
||||
|
||||
This helps users understand when to use the command.
|
||||
|
||||
### Format Defaults
|
||||
|
||||
- Shorthand flags: Infer format from flag
|
||||
- Result command: Defaults to JSON (most common for piping)
|
||||
- Can override with `--format` for result command
|
||||
|
||||
## Documentation Updates
|
||||
|
||||
### Updated Files
|
||||
|
||||
1. **CLI README** (`crates/cli/README.md`)
|
||||
- Added shorthand flag examples
|
||||
- Added result command documentation
|
||||
- Added scripting examples with jq
|
||||
- Updated all examples to use shorthand flags
|
||||
|
||||
2. **CLI Docs** (`docs/cli.md`)
|
||||
- Added global flags section with shorthands
|
||||
- Added result extraction examples
|
||||
- Updated scripting examples
|
||||
- Added integration examples
|
||||
|
||||
3. **Main README** (`README.md`)
|
||||
- Added shorthand flag quick examples
|
||||
- Added result extraction to CLI features
|
||||
- Updated feature highlights
|
||||
|
||||
## Backward Compatibility
|
||||
|
||||
✅ **Fully Backward Compatible**
|
||||
- `--output` flag still works
|
||||
- No changes to existing behavior
|
||||
- New flags are optional additions
|
||||
- All existing scripts continue to work
|
||||
|
||||
## Testing
|
||||
|
||||
### Manual Tests
|
||||
|
||||
```bash
|
||||
# Build
|
||||
cargo build -p attune-cli
|
||||
|
||||
# Test shorthand flags
|
||||
./target/debug/attune config list -j # Should output JSON
|
||||
./target/debug/attune config list -y # Should output YAML
|
||||
|
||||
# Test conflicts
|
||||
./target/debug/attune config list -j -y # Should error
|
||||
./target/debug/attune config list -j --output table # Should error
|
||||
|
||||
# Test result command
|
||||
./target/debug/attune execution result --help # Should show help
|
||||
```
|
||||
|
||||
### Build Status
|
||||
- ✅ Compiles successfully
|
||||
- ✅ No new warnings
|
||||
- ✅ Help text displays correctly
|
||||
- ✅ Conflict handling works
|
||||
|
||||
## Metrics
|
||||
|
||||
- **Files Modified**: 5
|
||||
- **Lines Added**: ~150
|
||||
- **New Command**: 1 (`execution result`)
|
||||
- **New Flags**: 2 (`-j`, `-y`)
|
||||
- **Documentation Updates**: 3 files
|
||||
- **Development Time**: ~45 minutes
|
||||
|
||||
## Files Changed
|
||||
|
||||
### Modified Files
|
||||
- `crates/cli/src/main.rs`: Added shorthand flags and resolution logic
|
||||
- `crates/cli/src/commands/execution.rs`: Added result command
|
||||
- `crates/cli/README.md`: Updated documentation
|
||||
- `docs/cli.md`: Updated documentation
|
||||
- `README.md`: Updated examples
|
||||
|
||||
## Future Enhancements
|
||||
|
||||
Potential improvements:
|
||||
1. **Result Templating**: `--template '{{.status}}: {{.message}}'`
|
||||
2. **JSONPath Support**: `--path '$.data.metrics'`
|
||||
3. **Output Streaming**: For large results
|
||||
4. **Format Conversion**: `--from json --to yaml`
|
||||
5. **Pretty Printing Options**: `--compact`, `--indent 2`
|
||||
6. **Result Diffing**: `attune execution diff 123 124`
|
||||
|
||||
## Comparison with Other Tools
|
||||
|
||||
Following conventions from popular CLI tools:
|
||||
|
||||
| Tool | JSON Flag | YAML Flag | Notes |
|
||||
|----------|-----------|-----------|--------------------------|
|
||||
| kubectl | `-o json` | `-o yaml` | Uses `-o` for output |
|
||||
| docker | `--format`| N/A | Uses Go templates |
|
||||
| jq | (default) | N/A | JSON only |
|
||||
| yq | N/A | (default) | YAML only |
|
||||
| **attune** | `-j` | `-y` | Convenient shorthands |
|
||||
|
||||
Our approach is more concise and follows the Unix tradition of single-letter flags for common options.
|
||||
|
||||
## Conclusion
|
||||
|
||||
Successfully enhanced the CLI with:
|
||||
- Unix-friendly shorthand output flags
|
||||
- Raw result extraction for piping
|
||||
- Better interoperability with standard tools
|
||||
- Improved scripting capabilities
|
||||
|
||||
The changes make the CLI more powerful for automation and integration with existing Unix toolchains, while maintaining full backward compatibility.
|
||||
|
||||
## Related Documents
|
||||
- [CLI README](../crates/cli/README.md)
|
||||
- [CLI Documentation](../docs/cli.md)
|
||||
- [CLI Implementation Work Summary](2026-01-18-cli-implementation.md)
|
||||
- [Execution Search Enhancement](2026-01-18-execution-search-enhancement.md)
|
||||
Reference in New Issue
Block a user