1287 lines
36 KiB
HTML
Raw Normal View History

<!DOCTYPE HTML>
<html lang="en" class="ayu sidebar-visible" dir="ltr">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Workflow - Provisioning Platform Documentation</title>
<!-- Custom HTML head -->
<meta name="description" content="Complete documentation for the Provisioning Platform - Infrastructure automation with Nushell, KCL, and Rust">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff">
<link rel="icon" href="../favicon.svg">
<link rel="shortcut icon" href="../favicon.png">
<link rel="stylesheet" href="../css/variables.css">
<link rel="stylesheet" href="../css/general.css">
<link rel="stylesheet" href="../css/chrome.css">
<link rel="stylesheet" href="../css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="../FontAwesome/css/font-awesome.css">
<link rel="stylesheet" href="../fonts/fonts.css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" id="highlight-css" href="../highlight.css">
<link rel="stylesheet" id="tomorrow-night-css" href="../tomorrow-night.css">
<link rel="stylesheet" id="ayu-highlight-css" href="../ayu-highlight.css">
<!-- Custom theme stylesheets -->
<!-- Provide site root and default themes to javascript -->
<script>
const path_to_root = "../";
const default_light_theme = "ayu";
const default_dark_theme = "navy";
</script>
<!-- Start loading toc.js asap -->
<script src="../toc.js"></script>
</head>
<body>
<div id="mdbook-help-container">
<div id="mdbook-help-popup">
<h2 class="mdbook-help-title">Keyboard shortcuts</h2>
<div>
<p>Press <kbd></kbd> or <kbd></kbd> to navigate between chapters</p>
<p>Press <kbd>S</kbd> or <kbd>/</kbd> to search in the book</p>
<p>Press <kbd>?</kbd> to show this help</p>
<p>Press <kbd>Esc</kbd> to hide this help</p>
</div>
</div>
</div>
<div id="body-container">
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script>
try {
let theme = localStorage.getItem('mdbook-theme');
let sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script>
const default_theme = window.matchMedia("(prefers-color-scheme: dark)").matches ? default_dark_theme : default_light_theme;
let theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
const html = document.documentElement;
html.classList.remove('ayu')
html.classList.add(theme);
html.classList.add("js");
</script>
<input type="checkbox" id="sidebar-toggle-anchor" class="hidden">
<!-- Hide / unhide sidebar before it is displayed -->
<script>
let sidebar = null;
const sidebar_toggle = document.getElementById("sidebar-toggle-anchor");
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
} else {
sidebar = 'hidden';
}
sidebar_toggle.checked = sidebar === 'visible';
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<!-- populated by js -->
<mdbook-sidebar-scrollbox class="sidebar-scrollbox"></mdbook-sidebar-scrollbox>
<noscript>
<iframe class="sidebar-iframe-outer" src="../toc.html"></iframe>
</noscript>
<div id="sidebar-resize-handle" class="sidebar-resize-handle">
<div class="sidebar-resize-indicator"></div>
</div>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar-hover-placeholder"></div>
<div id="menu-bar" class="menu-bar sticky">
<div class="left-buttons">
<label id="sidebar-toggle" class="icon-button" for="sidebar-toggle-anchor" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</label>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="default_theme">Auto</button></li>
<li role="none"><button role="menuitem" class="theme" id="light">Light</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search (`/`)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="/ s" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title">Provisioning Platform Documentation</h1>
<div class="right-buttons">
<a href="../print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform" title="Git repository" aria-label="Git repository">
<i id="git-repository-button" class="fa fa-github"></i>
</a>
<a href="https://github.com/provisioning/provisioning-platform/edit/main/provisioning/docs/src/development/workflow.md" title="Suggest an edit" aria-label="Suggest an edit">
<i id="git-edit-button" class="fa fa-edit"></i>
</a>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script>
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<h1 id="development-workflow-guide"><a class="header" href="#development-workflow-guide">Development Workflow Guide</a></h1>
<p>This document outlines the recommended development workflows, coding practices, testing strategies, and debugging techniques for the provisioning project.</p>
<h2 id="table-of-contents"><a class="header" href="#table-of-contents">Table of Contents</a></h2>
<ol>
<li><a href="#overview">Overview</a></li>
<li><a href="#development-setup">Development Setup</a></li>
<li><a href="#daily-development-workflow">Daily Development Workflow</a></li>
<li><a href="#code-organization">Code Organization</a></li>
<li><a href="#testing-strategies">Testing Strategies</a></li>
<li><a href="#debugging-techniques">Debugging Techniques</a></li>
<li><a href="#integration-workflows">Integration Workflows</a></li>
<li><a href="#collaboration-guidelines">Collaboration Guidelines</a></li>
<li><a href="#quality-assurance">Quality Assurance</a></li>
<li><a href="#best-practices">Best Practices</a></li>
</ol>
<h2 id="overview"><a class="header" href="#overview">Overview</a></h2>
<p>The provisioning project employs a multi-language, multi-component architecture requiring specific development workflows to maintain consistency, quality, and efficiency.</p>
<p><strong>Key Technologies</strong>:</p>
<ul>
<li><strong>Nushell</strong>: Primary scripting and automation language</li>
<li><strong>Rust</strong>: High-performance system components</li>
<li><strong>KCL</strong>: Configuration language and schemas</li>
<li><strong>TOML</strong>: Configuration files</li>
<li><strong>Jinja2</strong>: Template engine</li>
</ul>
<p><strong>Development Principles</strong>:</p>
<ul>
<li><strong>Configuration-Driven</strong>: Never hardcode, always configure</li>
<li><strong>Hybrid Architecture</strong>: Rust for performance, Nushell for flexibility</li>
<li><strong>Test-First</strong>: Comprehensive testing at all levels</li>
<li><strong>Documentation-Driven</strong>: Code and APIs are self-documenting</li>
</ul>
<h2 id="development-setup"><a class="header" href="#development-setup">Development Setup</a></h2>
<h3 id="initial-environment-setup"><a class="header" href="#initial-environment-setup">Initial Environment Setup</a></h3>
<p><strong>1. Clone and Navigate</strong>:</p>
<pre><code class="language-bash"># Clone repository
git clone https://github.com/company/provisioning-system.git
cd provisioning-system
# Navigate to workspace
cd workspace/tools
```plaintext
**2. Initialize Workspace**:
```bash
# Initialize development workspace
nu workspace.nu init --user-name $USER --infra-name dev-env
# Check workspace health
nu workspace.nu health --detailed --fix-issues
```plaintext
**3. Configure Development Environment**:
```bash
# Create user configuration
cp workspace/config/local-overrides.toml.example workspace/config/$USER.toml
# Edit configuration for development
$EDITOR workspace/config/$USER.toml
```plaintext
**4. Set Up Build System**:
```bash
# Navigate to build tools
cd src/tools
# Check build prerequisites
make info
# Perform initial build
make dev-build
```plaintext
### Tool Installation
**Required Tools**:
```bash
# Install Nushell
cargo install nu
# Install KCL
cargo install kcl-cli
# Install additional tools
cargo install cross # Cross-compilation
cargo install cargo-audit # Security auditing
cargo install cargo-watch # File watching
```plaintext
**Optional Development Tools**:
```bash
# Install development enhancers
cargo install nu_plugin_tera # Template plugin
cargo install sops # Secrets management
brew install k9s # Kubernetes management
```plaintext
### IDE Configuration
**VS Code Setup** (`.vscode/settings.json`):
```json
{
"files.associations": {
"*.nu": "shellscript",
"*.k": "kcl",
"*.toml": "toml"
},
"nushell.shellPath": "/usr/local/bin/nu",
"rust-analyzer.cargo.features": "all",
"editor.formatOnSave": true,
"editor.rulers": [100],
"files.trimTrailingWhitespace": true
}
```plaintext
**Recommended Extensions**:
- Nushell Language Support
- Rust Analyzer
- KCL Language Support
- TOML Language Support
- Better TOML
## Daily Development Workflow
### Morning Routine
**1. Sync and Update**:
```bash
# Sync with upstream
git pull origin main
# Update workspace
cd workspace/tools
nu workspace.nu health --fix-issues
# Check for updates
nu workspace.nu status --detailed
```plaintext
**2. Review Current State**:
```bash
# Check current infrastructure
provisioning show servers
provisioning show settings
# Review workspace status
nu workspace.nu status
```plaintext
### Development Cycle
**1. Feature Development**:
```bash
# Create feature branch
git checkout -b feature/new-provider-support
# Start development environment
cd workspace/tools
nu workspace.nu init --workspace-type development
# Begin development
$EDITOR workspace/extensions/providers/new-provider/nulib/provider.nu
```plaintext
**2. Incremental Testing**:
```bash
# Test syntax during development
nu --check workspace/extensions/providers/new-provider/nulib/provider.nu
# Run unit tests
nu workspace/extensions/providers/new-provider/tests/unit/basic-test.nu
# Integration testing
nu workspace.nu tools test-extension providers/new-provider
```plaintext
**3. Build and Validate**:
```bash
# Quick development build
cd src/tools
make dev-build
# Validate changes
make validate-all
# Test distribution
make test-dist
```plaintext
### Testing During Development
**Unit Testing**:
```nushell
# Add test examples to functions
def create-server [name: string] -&gt; record {
# @test: "test-server" -&gt; {name: "test-server", status: "created"}
# Implementation here
}
```plaintext
**Integration Testing**:
```bash
# Test with real infrastructure
nu workspace/extensions/providers/new-provider/nulib/provider.nu \
create-server test-server --dry-run
# Test with workspace isolation
PROVISIONING_WORKSPACE_USER=$USER provisioning server create test-server --check
```plaintext
### End-of-Day Routine
**1. Commit Progress**:
```bash
# Stage changes
git add .
# Commit with descriptive message
git commit -m "feat(provider): add new cloud provider support
- Implement basic server creation
- Add configuration schema
- Include unit tests
- Update documentation"
# Push to feature branch
git push origin feature/new-provider-support
```plaintext
**2. Workspace Maintenance**:
```bash
# Clean up development data
nu workspace.nu cleanup --type cache --age 1d
# Backup current state
nu workspace.nu backup --auto-name --components config,extensions
# Check workspace health
nu workspace.nu health
```plaintext
## Code Organization
### Nushell Code Structure
**File Organization**:
```plaintext
Extension Structure:
├── nulib/
│ ├── main.nu # Main entry point
│ ├── core/ # Core functionality
│ │ ├── api.nu # API interactions
│ │ ├── config.nu # Configuration handling
│ │ └── utils.nu # Utility functions
│ ├── commands/ # User commands
│ │ ├── create.nu # Create operations
│ │ ├── delete.nu # Delete operations
│ │ └── list.nu # List operations
│ └── tests/ # Test files
│ ├── unit/ # Unit tests
│ └── integration/ # Integration tests
└── templates/ # Template files
├── config.j2 # Configuration templates
└── manifest.j2 # Manifest templates
```plaintext
**Function Naming Conventions**:
```nushell
# Use kebab-case for commands
def create-server [name: string] -&gt; record { ... }
def validate-config [config: record] -&gt; bool { ... }
# Use snake_case for internal functions
def get_api_client [] -&gt; record { ... }
def parse_config_file [path: string] -&gt; record { ... }
# Use descriptive prefixes
def check-server-status [server: string] -&gt; string { ... }
def get-server-info [server: string] -&gt; record { ... }
def list-available-zones [] -&gt; list&lt;string&gt; { ... }
```plaintext
**Error Handling Pattern**:
```nushell
def create-server [
name: string
--dry-run: bool = false
] -&gt; record {
# 1. Validate inputs
if ($name | str length) == 0 {
error make {
msg: "Server name cannot be empty"
label: {
text: "empty name provided"
span: (metadata $name).span
}
}
}
# 2. Check prerequisites
let config = try {
get-provider-config
} catch {
error make {msg: "Failed to load provider configuration"}
}
# 3. Perform operation
if $dry_run {
return {action: "create", server: $name, status: "dry-run"}
}
# 4. Return result
{server: $name, status: "created", id: (generate-id)}
}
```plaintext
### Rust Code Structure
**Project Organization**:
```plaintext
src/
├── lib.rs # Library root
├── main.rs # Binary entry point
├── config/ # Configuration handling
│ ├── mod.rs
│ ├── loader.rs # Config loading
│ └── validation.rs # Config validation
├── api/ # HTTP API
│ ├── mod.rs
│ ├── handlers.rs # Request handlers
│ └── middleware.rs # Middleware components
└── orchestrator/ # Orchestration logic
├── mod.rs
├── workflow.rs # Workflow management
└── task_queue.rs # Task queue management
```plaintext
**Error Handling**:
```rust
use anyhow::{Context, Result};
use thiserror::Error;
#[derive(Error, Debug)]
pub enum ProvisioningError {
#[error("Configuration error: {message}")]
Config { message: String },
#[error("Network error: {source}")]
Network {
#[from]
source: reqwest::Error,
},
#[error("Validation failed: {field}")]
Validation { field: String },
}
pub fn create_server(name: &amp;str) -&gt; Result&lt;ServerInfo&gt; {
let config = load_config()
.context("Failed to load configuration")?;
validate_server_name(name)
.context("Server name validation failed")?;
let server = provision_server(name, &amp;config)
.context("Failed to provision server")?;
Ok(server)
}
```plaintext
### KCL Schema Organization
**Schema Structure**:
```kcl
# Base schema definitions
schema ServerConfig:
name: str
plan: str
zone: str
tags?: {str: str} = {}
check:
len(name) &gt; 0, "Server name cannot be empty"
plan in ["1xCPU-2GB", "2xCPU-4GB", "4xCPU-8GB"], "Invalid plan"
# Provider-specific extensions
schema UpCloudServerConfig(ServerConfig):
template?: str = "Ubuntu Server 22.04 LTS (Jammy Jellyfish)"
storage?: int = 25
check:
storage &gt;= 10, "Minimum storage is 10GB"
storage &lt;= 2048, "Maximum storage is 2TB"
# Composition schemas
schema InfrastructureConfig:
servers: [ServerConfig]
networks?: [NetworkConfig] = []
load_balancers?: [LoadBalancerConfig] = []
check:
len(servers) &gt; 0, "At least one server required"
```plaintext
## Testing Strategies
### Test-Driven Development
**TDD Workflow**:
1. **Write Test First**: Define expected behavior
2. **Run Test (Fail)**: Confirm test fails as expected
3. **Write Code**: Implement minimal code to pass
4. **Run Test (Pass)**: Confirm test now passes
5. **Refactor**: Improve code while keeping tests green
### Nushell Testing
**Unit Test Pattern**:
```nushell
# Function with embedded test
def validate-server-name [name: string] -&gt; bool {
# @test: "valid-name" -&gt; true
# @test: "" -&gt; false
# @test: "name-with-spaces" -&gt; false
if ($name | str length) == 0 {
return false
}
if ($name | str contains " ") {
return false
}
true
}
# Separate test file
# tests/unit/server-validation-test.nu
def test_validate_server_name [] {
# Valid cases
assert (validate-server-name "valid-name")
assert (validate-server-name "server123")
# Invalid cases
assert not (validate-server-name "")
assert not (validate-server-name "name with spaces")
assert not (validate-server-name "name@with!special")
print "✅ validate-server-name tests passed"
}
```plaintext
**Integration Test Pattern**:
```nushell
# tests/integration/server-lifecycle-test.nu
def test_complete_server_lifecycle [] {
# Setup
let test_server = "test-server-" + (date now | format date "%Y%m%d%H%M%S")
try {
# Test creation
let create_result = (create-server $test_server --dry-run)
assert ($create_result.status == "dry-run")
# Test validation
let validate_result = (validate-server-config $test_server)
assert $validate_result
print $"✅ Server lifecycle test passed for ($test_server)"
} catch { |e|
print $"❌ Server lifecycle test failed: ($e.msg)"
exit 1
}
}
```plaintext
### Rust Testing
**Unit Testing**:
```rust
#[cfg(test)]
mod tests {
use super::*;
use tokio_test;
#[test]
fn test_validate_server_name() {
assert!(validate_server_name("valid-name"));
assert!(validate_server_name("server123"));
assert!(!validate_server_name(""));
assert!(!validate_server_name("name with spaces"));
assert!(!validate_server_name("name@special"));
}
#[tokio::test]
async fn test_server_creation() {
let config = test_config();
let result = create_server("test-server", &amp;config).await;
assert!(result.is_ok());
let server = result.unwrap();
assert_eq!(server.name, "test-server");
assert_eq!(server.status, "created");
}
}
```plaintext
**Integration Testing**:
```rust
#[cfg(test)]
mod integration_tests {
use super::*;
use testcontainers::*;
#[tokio::test]
async fn test_full_workflow() {
// Setup test environment
let docker = clients::Cli::default();
let postgres = docker.run(images::postgres::Postgres::default());
let config = TestConfig {
database_url: format!("postgresql://localhost:{}/test",
postgres.get_host_port_ipv4(5432))
};
// Test complete workflow
let workflow = create_workflow(&amp;config).await.unwrap();
let result = execute_workflow(workflow).await.unwrap();
assert_eq!(result.status, WorkflowStatus::Completed);
}
}
```plaintext
### KCL Testing
**Schema Validation Testing**:
```bash
# Test KCL schemas
kcl test kcl/
# Validate specific schemas
kcl check kcl/server.k --data test-data.yaml
# Test with examples
kcl run kcl/server.k -D name="test-server" -D plan="2xCPU-4GB"
```plaintext
### Test Automation
**Continuous Testing**:
```bash
# Watch for changes and run tests
cargo watch -x test -x check
# Watch Nushell files
find . -name "*.nu" | entr -r nu tests/run-all-tests.nu
# Automated testing in workspace
nu workspace.nu tools test-all --watch
```plaintext
## Debugging Techniques
### Debug Configuration
**Enable Debug Mode**:
```bash
# Environment variables
export PROVISIONING_DEBUG=true
export PROVISIONING_LOG_LEVEL=debug
export RUST_LOG=debug
export RUST_BACKTRACE=1
# Workspace debug
export PROVISIONING_WORKSPACE_USER=$USER
```plaintext
### Nushell Debugging
**Debug Techniques**:
```nushell
# Debug prints
def debug-server-creation [name: string] {
print $"🐛 Creating server: ($name)"
let config = get-provider-config
print $"🐛 Config loaded: ($config | to json)"
let result = try {
create-server-api $name $config
} catch { |e|
print $"🐛 API call failed: ($e.msg)"
$e
}
print $"🐛 Result: ($result | to json)"
$result
}
# Conditional debugging
def create-server [name: string] {
if $env.PROVISIONING_DEBUG? == "true" {
print $"Debug: Creating server ($name)"
}
# Implementation
}
# Interactive debugging
def debug-interactive [] {
print "🐛 Entering debug mode..."
print "Available commands: $env.PATH"
print "Current config: " (get-config | to json)
# Drop into interactive shell
nu --interactive
}
```plaintext
**Error Investigation**:
```nushell
# Comprehensive error handling
def safe-server-creation [name: string] {
try {
create-server $name
} catch { |e|
# Log error details
{
timestamp: (date now | format date "%Y-%m-%d %H:%M:%S"),
operation: "create-server",
input: $name,
error: $e.msg,
debug: $e.debug?,
env: {
user: $env.USER,
workspace: $env.PROVISIONING_WORKSPACE_USER?,
debug: $env.PROVISIONING_DEBUG?
}
} | save --append logs/error-debug.json
# Re-throw with context
error make {
msg: $"Server creation failed: ($e.msg)",
label: {text: "failed here", span: $e.span?}
}
}
}
```plaintext
### Rust Debugging
**Debug Logging**:
```rust
use tracing::{debug, info, warn, error, instrument};
#[instrument]
pub async fn create_server(name: &amp;str) -&gt; Result&lt;ServerInfo&gt; {
debug!("Starting server creation for: {}", name);
let config = load_config()
.map_err(|e| {
error!("Failed to load config: {:?}", e);
e
})?;
info!("Configuration loaded successfully");
debug!("Config details: {:?}", config);
let server = provision_server(name, &amp;config).await
.map_err(|e| {
error!("Provisioning failed for {}: {:?}", name, e);
e
})?;
info!("Server {} created successfully", name);
Ok(server)
}
```plaintext
**Interactive Debugging**:
```rust
// Use debugger breakpoints
#[cfg(debug_assertions)]
{
println!("Debug: server creation starting");
dbg!(&amp;config);
// Add breakpoint here in IDE
}
```plaintext
### Log Analysis
**Log Monitoring**:
```bash
# Follow all logs
tail -f workspace/runtime/logs/$USER/*.log
# Filter for errors
grep -i error workspace/runtime/logs/$USER/*.log
# Monitor specific component
tail -f workspace/runtime/logs/$USER/orchestrator.log | grep -i workflow
# Structured log analysis
jq '.level == "ERROR"' workspace/runtime/logs/$USER/structured.jsonl
```plaintext
**Debug Log Levels**:
```bash
# Different verbosity levels
PROVISIONING_LOG_LEVEL=trace provisioning server create test
PROVISIONING_LOG_LEVEL=debug provisioning server create test
PROVISIONING_LOG_LEVEL=info provisioning server create test
```plaintext
## Integration Workflows
### Existing System Integration
**Working with Legacy Components**:
```bash
# Test integration with existing system
provisioning --version # Legacy system
src/core/nulib/provisioning --version # New system
# Test workspace integration
PROVISIONING_WORKSPACE_USER=$USER provisioning server list
# Validate configuration compatibility
provisioning validate config
nu workspace.nu config validate
```plaintext
### API Integration Testing
**REST API Testing**:
```bash
# Test orchestrator API
curl -X GET http://localhost:9090/health
curl -X GET http://localhost:9090/tasks
# Test workflow creation
curl -X POST http://localhost:9090/workflows/servers/create \
-H "Content-Type: application/json" \
-d '{"name": "test-server", "plan": "2xCPU-4GB"}'
# Monitor workflow
curl -X GET http://localhost:9090/workflows/batch/status/workflow-id
```plaintext
### Database Integration
**SurrealDB Integration**:
```nushell
# Test database connectivity
use core/nulib/lib_provisioning/database/surreal.nu
let db = (connect-database)
(test-connection $db)
# Workflow state testing
let workflow_id = (create-workflow-record "test-workflow")
let status = (get-workflow-status $workflow_id)
assert ($status.status == "pending")
```plaintext
### External Tool Integration
**Container Integration**:
```bash
# Test with Docker
docker run --rm -v $(pwd):/work provisioning:dev provisioning --version
# Test with Kubernetes
kubectl apply -f manifests/test-pod.yaml
kubectl logs test-pod
# Validate in different environments
make test-dist PLATFORM=docker
make test-dist PLATFORM=kubernetes
```plaintext
## Collaboration Guidelines
### Branch Strategy
**Branch Naming**:
- `feature/description` - New features
- `fix/description` - Bug fixes
- `docs/description` - Documentation updates
- `refactor/description` - Code refactoring
- `test/description` - Test improvements
**Workflow**:
```bash
# Start new feature
git checkout main
git pull origin main
git checkout -b feature/new-provider-support
# Regular commits
git add .
git commit -m "feat(provider): implement server creation API"
# Push and create PR
git push origin feature/new-provider-support
gh pr create --title "Add new provider support" --body "..."
```plaintext
### Code Review Process
**Review Checklist**:
- [ ] Code follows project conventions
- [ ] Tests are included and passing
- [ ] Documentation is updated
- [ ] No hardcoded values
- [ ] Error handling is comprehensive
- [ ] Performance considerations addressed
**Review Commands**:
```bash
# Test PR locally
gh pr checkout 123
cd src/tools &amp;&amp; make ci-test
# Run specific tests
nu workspace/extensions/providers/new-provider/tests/run-all.nu
# Check code quality
cargo clippy -- -D warnings
nu --check $(find . -name "*.nu")
```plaintext
### Documentation Requirements
**Code Documentation**:
```nushell
# Function documentation
def create-server [
name: string # Server name (must be unique)
plan: string # Server plan (e.g., "2xCPU-4GB")
--dry-run: bool # Show what would be created without doing it
] -&gt; record { # Returns server creation result
# Creates a new server with the specified configuration
#
# Examples:
# create-server "web-01" "2xCPU-4GB"
# create-server "test" "1xCPU-2GB" --dry-run
# Implementation
}
```plaintext
### Communication
**Progress Updates**:
- Daily standup participation
- Weekly architecture reviews
- PR descriptions with context
- Issue tracking with details
**Knowledge Sharing**:
- Technical blog posts
- Architecture decision records
- Code review discussions
- Team documentation updates
## Quality Assurance
### Code Quality Checks
**Automated Quality Gates**:
```bash
# Pre-commit hooks
pre-commit install
# Manual quality check
cd src/tools
make validate-all
# Security audit
cargo audit
```plaintext
**Quality Metrics**:
- Code coverage &gt; 80%
- No critical security vulnerabilities
- All tests passing
- Documentation coverage complete
- Performance benchmarks met
### Performance Monitoring
**Performance Testing**:
```bash
# Benchmark builds
make benchmark
# Performance profiling
cargo flamegraph --bin provisioning-orchestrator
# Load testing
ab -n 1000 -c 10 http://localhost:9090/health
```plaintext
**Resource Monitoring**:
```bash
# Monitor during development
nu workspace/tools/runtime-manager.nu monitor --duration 5m
# Check resource usage
du -sh workspace/runtime/
df -h
```plaintext
## Best Practices
### Configuration Management
**Never Hardcode**:
```nushell
# Bad
def get-api-url [] { "https://api.upcloud.com" }
# Good
def get-api-url [] {
get-config-value "providers.upcloud.api_url" "https://api.upcloud.com"
}
```plaintext
### Error Handling
**Comprehensive Error Context**:
```nushell
def create-server [name: string] {
try {
validate-server-name $name
} catch { |e|
error make {
msg: $"Invalid server name '($name)': ($e.msg)",
label: {text: "server name validation failed", span: $e.span?}
}
}
try {
provision-server $name
} catch { |e|
error make {
msg: $"Server provisioning failed for '($name)': ($e.msg)",
help: "Check provider credentials and quota limits"
}
}
}
```plaintext
### Resource Management
**Clean Up Resources**:
```nushell
def with-temporary-server [name: string, action: closure] {
let server = (create-server $name)
try {
do $action $server
} catch { |e|
# Clean up on error
delete-server $name
$e
}
# Clean up on success
delete-server $name
}
```plaintext
### Testing Best Practices
**Test Isolation**:
```nushell
def test-with-isolation [test_name: string, test_action: closure] {
let test_workspace = $"test-($test_name)-(date now | format date '%Y%m%d%H%M%S')"
try {
# Set up isolated environment
$env.PROVISIONING_WORKSPACE_USER = $test_workspace
nu workspace.nu init --user-name $test_workspace
# Run test
do $test_action
print $"✅ Test ($test_name) passed"
} catch { |e|
print $"❌ Test ($test_name) failed: ($e.msg)"
exit 1
} finally {
# Clean up test environment
nu workspace.nu cleanup --user-name $test_workspace --type all --force
}
}
```plaintext
This development workflow provides a comprehensive framework for efficient, quality-focused development while maintaining the project's architectural principles and ensuring smooth collaboration across the team.
</code></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="../development/configuration.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../development/integration.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a rel="prev" href="../development/configuration.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next prefetch" href="../development/integration.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script>
window.playground_copyable = true;
</script>
<script src="../elasticlunr.min.js"></script>
<script src="../mark.min.js"></script>
<script src="../searcher.js"></script>
<script src="../clipboard.min.js"></script>
<script src="../highlight.js"></script>
<script src="../book.js"></script>
<!-- Custom JS scripts -->
</div>
</body>
</html>