# Arger - Parameters Across Languages

Effective parameter handling is fundamental to building flexible, maintainable automation systems. This guide explores how different languages and tools approach parameter management, using a user account creation scenario as our running example.

## The Use Case

We'll examine how to handle user account parameters across different contexts:

* **username**: The account identifier
    
* **address**: Physical or mailing address
    
* **phone**: Contact phone number
    
* **email**: Email address
    

## Python: Function Arguments and Environment Variables

Python offers multiple approaches to parameter handling. The most straightforward method uses function arguments with type hints and default values:

```python
# user_manager.py
import sys
import os

def create_user(username: str, email: str, address: str = "", phone: str = "") -> dict:
    """
    Create a user account with the provided parameters.
    
    Args:
        username: Required username for the account
        email: Required email address
        address: Optional physical address
        phone: Optional phone number
    
    Returns:
        Dictionary containing user details
    """
    user_data = {
        "username": username,
        "email": email,
        "address": address if address else "Not provided",
        "phone": phone if phone else "Not provided"
    }
    
    print(f"Creating user account:")
    for key, value in user_data.items():
        print(f"  {key}: {value}")
    
    return user_data

def main():
    # Method 1: Command-line arguments
    if len(sys.argv) >= 3:
        username = sys.argv[1]
        email = sys.argv[2]
        address = sys.argv[3] if len(sys.argv) > 3 else ""
        phone = sys.argv[4] if len(sys.argv) > 4 else ""
    else:
        # Method 2: Environment variables as fallback
        username = os.getenv("USERNAME", "default_user")
        email = os.getenv("EMAIL", "user@example.com")
        address = os.getenv("ADDRESS", "")
        phone = os.getenv("PHONE", "")
    
    create_user(username, email, address, phone)

if __name__ == "__main__":
    main()
```

Python's flexibility allows you to combine multiple parameter sources, with command-line arguments taking precedence over environment variables.

The standard library has [argparse](https://docs.python.org/3/library/argparse.html), and whole page for [choosing an argument parser](https://docs.python.org/3/library/optparse.html#choosing-an-argument-parser). There are excellent packages to create CLIs like [typer](https://typer.tiangolo.com/) and [click](https://click.palletsprojects.com/en/stable/).

## Bash: Positional Parameters and Named Variables

Bash scripts use positional parameters and can validate their presence before execution:

```bash
#!/bin/bash
# create_user.sh

# Function to create user with parameters
create_user() {
    local username=$1
    local email=$2
    local address=${3:-"Not provided"}
    local phone=${4:-"Not provided"}
    
    echo "Creating user account:"
    echo "  username: $username"
    echo "  email: $email"
    echo "  address: $address"
    echo "  phone: $phone"
    
    # Simulate user creation
    echo "User account created successfully"
}

# Validate required parameters
if [ $# -lt 2 ]; then
    echo "Error: Missing required parameters"
    echo "Usage: $0 <username> <email> [address] [phone]"
    exit 1
fi

# Extract parameters
USERNAME=$1
EMAIL=$2
ADDRESS=${3:-""}
PHONE=${4:-""}

# Call the function
create_user "$USERNAME" "$EMAIL" "$ADDRESS" "$PHONE"
```

The `${variable:-default}` syntax provides a clean way to specify default values for optional parameters.

## Dockerfile: Build Arguments and Environment Variables

Dockerfiles distinguish between build-time arguments (ARG) and runtime environment variables (ENV):

```dockerfile
# Dockerfile
FROM python:3.9-slim

# Build-time arguments with defaults
ARG APP_VERSION=1.0.0
ARG PYTHON_ENV=production

# Set environment variables for runtime
ENV USERNAME=""
ENV EMAIL=""
ENV ADDRESS=""
ENV PHONE=""

# Create application directory
WORKDIR /app

# Copy application files
COPY user_manager.py .
COPY create_user.sh .

# Make bash script executable
RUN chmod +x create_user.sh

# Install any required packages
RUN pip install --no-cache-dir --upgrade pip

# Default command
CMD ["python", "user_manager.py"]
```

You can override these at build time:

```bash
docker build --build-arg APP_VERSION=2.0.0 -t user-manager .
```

And at runtime:

```bash
docker run -e USERNAME="jdoe" -e EMAIL="jdoe@example.com" user-manager
```

## Jenkinsfile: Declarative Pipeline Parameters

Jenkins pipelines provide a structured approach to parameter handling through the parameters directive:

```plaintext
pipeline {
    agent any
    
    parameters {
        string(
            name: 'USERNAME',
            defaultValue: 'testuser',
            description: 'Username for the account',
            trim: true
        )
        string(
            name: 'EMAIL',
            defaultValue: 'test@example.com',
            description: 'Email address',
            trim: true
        )
        string(
            name: 'ADDRESS',
            defaultValue: '',
            description: 'Physical address (optional)',
            trim: true
        )
        string(
            name: 'PHONE',
            defaultValue: '',
            description: 'Phone number (optional)',
            trim: true
        )
        choice(
            name: 'EXECUTION_MODE',
            choices: ['python', 'bash', 'docker'],
            description: 'Which implementation to execute'
        )
    }
    
    environment {
        SCRIPT_DIR = "${WORKSPACE}"
    }
    
    stages {
        stage('Validate Parameters') {
            steps {
                script {
                    echo "Validating parameters..."
                    
                    if (params.USERNAME.isEmpty()) {
                        error("USERNAME parameter is required")
                    }
                    
                    if (params.EMAIL.isEmpty()) {
                        error("EMAIL parameter is required")
                    }
                    
                    // Basic email validation
                    if (!params.EMAIL.contains('@')) {
                        error("EMAIL must be a valid email address")
                    }
                    
                    echo "Parameter validation passed"
                }
            }
        }
        
        stage('Display Parameters') {
            steps {
                echo "Received parameters:"
                echo "  Username: ${params.USERNAME}"
                echo "  Email: ${params.EMAIL}"
                echo "  Address: ${params.ADDRESS ?: 'Not provided'}"
                echo "  Phone: ${params.PHONE ?: 'Not provided'}"
                echo "  Execution Mode: ${params.EXECUTION_MODE}"
            }
        }
        
        stage('Execute Python Script') {
            when {
                expression { params.EXECUTION_MODE == 'python' }
            }
            steps {
                script {
                    echo "Executing Python implementation..."
                    sh """
                        python3 user_manager.py \
                            '${params.USERNAME}' \
                            '${params.EMAIL}' \
                            '${params.ADDRESS}' \
                            '${params.PHONE}'
                    """
                }
            }
        }
        
        stage('Execute Bash Script') {
            when {
                expression { params.EXECUTION_MODE == 'bash' }
            }
            steps {
                script {
                    echo "Executing Bash implementation..."
                    sh """
                        chmod +x create_user.sh
                        ./create_user.sh \
                            '${params.USERNAME}' \
                            '${params.EMAIL}' \
                            '${params.ADDRESS}' \
                            '${params.PHONE}'
                    """
                }
            }
        }
        
        stage('Execute Docker Container') {
            when {
                expression { params.EXECUTION_MODE == 'docker' }
            }
            steps {
                script {
                    echo "Building and executing Docker implementation..."
                    sh """
                        docker build -t user-manager:latest .
                        docker run --rm \
                            -e USERNAME='${params.USERNAME}' \
                            -e EMAIL='${params.EMAIL}' \
                            -e ADDRESS='${params.ADDRESS}' \
                            -e PHONE='${params.PHONE}' \
                            user-manager:latest
                    """
                }
            }
        }
        
        stage('Report Results') {
            steps {
                script {
                    echo "User account creation process completed"
                    echo "Summary:"
                    echo "  Method used: ${params.EXECUTION_MODE}"
                    echo "  Account created for: ${params.USERNAME}"
                }
            }
        }
    }
    
    post {
        success {
            echo "Pipeline completed successfully"
        }
        failure {
            echo "Pipeline failed - check logs for details"
        }
        always {
            cleanWs()
        }
    }
}
```

## Takeaways

Each language and tool offers distinct advantages for parameter handling:

**Python** excels at combining multiple parameter sources with clear type hints and validation. The language's flexibility makes it ideal for complex parameter processing logic.

**Bash** provides straightforward positional parameters with simple default value syntax. It's particularly effective for system-level scripting where parameters flow directly from command invocation.

**Dockerfile** separates build-time configuration (ARG) from runtime configuration (ENV), enabling flexible container deployment strategies across different environments.

**Jenkins** offers a declarative, UI-friendly approach to parameters with built-in validation and type safety. The parameters directive creates an intuitive interface for operators while maintaining programmatic access in pipeline code.

## Best Practices

1. **Always validate required parameters** before processing begins
    
2. **Provide sensible defaults** for optional parameters
    
3. **Document parameter purposes** through comments or descriptions
    
4. **Use consistent naming conventions** across all implementations
    
5. **Escape parameters properly** when passing between systems to prevent injection vulnerabilities
    
6. **Consider parameter sensitivity** and avoid logging credentials or personal information
    

# Arger

By understanding how each tool handles parameters, you can build robust automation workflows that adapt to different execution contexts while maintaining consistency and reliability.

However, it can be a pain to write the boilerplate code, especially when you change the parameters. Updating the same across the entire pipeline can get boring quick. So, I created an app to generate the code using Opal.

It takes two inputs:

1. Parameter name and type
    
2. Languages to generate the code, like Python, Bash, Jenkinsfile, and Dockerfile.
    

Then, it will generate the code required to handle these parameters. Here’s the link:

%[https://opal.google/?flow=drive:/10OvX-kIAz2GG55UCsJFaQEQWl_aqIASv&shared&mode=app] 

> Arger
> 
> "Arger" can refer to the German word "Ärger," which means **<mark>"annoyance," "irritation," or "trouble"</mark>**. It can also refer to the German verb "ärgern," which means "to annoy," "to irritate," or "to anger". Less commonly, "Arger" might be a surname or a personal name of various origins.
