Skip to main content

A tool to create deployment folders based on YAML configuration

Project description

DeployFolder

A tool to create deployment folders based on YAML configuration. This tool helps you create structured deployment folders by copying files from source locations, optionally renaming them, and creating empty folders as needed.

Features

  • Create deployment folders with a specified structure
  • Copy files from source to target paths
  • Support for glob patterns (wildcards like *) in source file paths
  • Optionally rename files during copying
  • Support for placeholders in filenames and folder names
  • Replace placeholders with values from a JSON file
  • Create empty folders
  • Generate files from Jinja2 templates (inline or from external files)
  • Optionally zip the created folder
  • Cross-platform compatibility (Windows and Linux)

Installation

Install from PyPI (Python 3.7+):

pip install deployfolder

Optional: with 7z support

pip install deployfolder[7z]

Dependencies: PyYAML (MIT) and Jinja2 (BSD-3-Clause). The optional [7z] extra uses py7zr (LGPL-2.1+); install it only if you need 7z archives. See the upstream projects for the full license texts.

Usage

Using the Command-line Interface

After installing the package:

deployfolder config.yaml [--values values.json]

Arguments

  • config.yaml: Path to the YAML configuration file (required)
  • --values values.json: Path to the JSON values file for placeholder replacement (optional)
  • --version: Show version information and exit

Configuration File Format

The YAML configuration file defines the structure of the deployment folder:

output_folder: "folder_name"  # Optional, defaults to "deploy"
archive: true                 # Optional, defaults to false
files:                        # List of files to copy or folders to create
  # Simple file copy (keeps original filename in root directory)
  - "path/to/source/file.txt"
  
  # Copy with original filename to a subdirectory
  - source: "path/to/source/file.txt"
    directory: "docs"
  
  # Copy with original filename to a subdirectory with placeholder
  - source: "path/to/source/file.txt"
    directory: "{{ environment }}/docs"
  
  # Copy with renaming
  - source: "path/to/source/file.txt"
    target: "new_name.txt"
  
  # Copy with placeholders in target name
  - source: "path/to/source/config.ini"
    target: "{{ environment }}_config.ini"
  
  # Create empty folder
  - target: "logs/{{ environment }}"

templates:                    # List of templates to render
  # Template with inline content
  - content: |
      # Generated Configuration
      # Generated on: {{ date }}
      
      [Application]
      Name = {{ project_name }}
      Environment = {{ environment }}
    target: "config/generated_config.ini"
  
  # Template from external file
  - file: "path/to/template.txt"
    target: "reports/{{ date }}_report.txt"

File Configuration Options

When configuring files in the YAML configuration, you have several options:

  1. Simple string format: Just specify the source path. The file will be copied to the root of the output folder with its original filename.

    - "path/to/source/file.txt"
    

    You can also use glob patterns to match multiple files:

    - "path/to/source/*.txt"  # Matches all .txt files in the directory
    - "path/to/source/file?.txt"  # Matches file1.txt, file2.txt, etc.
    - "path/to/source/[abc]*.txt"  # Matches files starting with a, b, or c
    
  2. Directory format: Specify both source and directory. The file will be copied to the specified subdirectory while keeping its original filename.

    - source: "path/to/source/file.txt"
      directory: "docs"
    

    Glob patterns are also supported in the source path:

    - source: "path/to/source/*.txt"
      directory: "docs"  # All matching files will be copied to the docs directory
    
  3. Target format: Specify both source and target. The file will be copied to the specified target path, which can include a new filename.

    - source: "path/to/source/file.txt"
      target: "new_name.txt"
    

    When using glob patterns with a target, there are two behaviors:

    # If target ends with / or \, it's treated as a directory
    - source: "path/to/source/*.txt"
      target: "text_files/"  # All matching files will be copied to the text_files directory
    
    # If target doesn't end with / or \, only the first matching file will be used
    - source: "path/to/source/*.txt"
      target: "first_text_file.txt"  # Only the first matching file will be copied and renamed
    
  4. Empty folder: Specify only target. An empty folder will be created at the specified path.

    - target: "logs/temp"
    

Template Configuration Options

When configuring templates in the YAML configuration, you have two main options:

  1. Inline template content: Specify both content and target. The template content will be rendered and saved to the specified target path.

    - content: |
        # Generated Configuration
        # Generated on: {{ date }}
        
        [Application]
        Name = {{ project_name }}
        Environment = {{ environment }}
      target: "config/generated_config.ini"
    
  2. External template file: Specify both file and target. The template file will be loaded, rendered, and saved to the specified target path.

    - file: "path/to/template.txt"
      target: "reports/{{ date }}_report.txt"
    

Templates support all Jinja2 features, including:

  • Placeholders (e.g., {{ variable }})
  • Conditionals (e.g., {% if condition %}...{% else %}...{% endif %})
  • Loops (e.g., {% for item in items %}...{% endfor %})
  • Filters (e.g., {{ variable | default('default value') }})
  • And more advanced Jinja2 features

The target path can include placeholders that will be replaced with values from the JSON values file, just like with file targets.

Placeholders

Placeholders in the format {{ name }} can be used in:

  • The output folder name
  • Target file names
  • Target folder names
  • Directory paths

Placeholders are replaced with values from the JSON values file.

Nested JSON Support

The tool supports accessing nested JSON properties using dot notation in placeholders. For example:

  • {{ user.name }} - Accesses the "name" property inside the "user" object
  • {{ database.host }} - Accesses the "host" property inside the "database" object
  • {{ database.credentials.username }} - Accesses deeply nested properties

This allows for more structured and organized values files, especially for complex configurations.

Values File Format

The JSON values file provides values for placeholders:

{
    "project_name": "MyProject",
    "environment": "production",
    "date": "2023-01-01"
}

Examples

Example Configuration (example_config.yaml)

output_folder: "{{ project_name }}_deploy"
archive: true
files:
  # Simple file copy (keeps original filename in root directory)
  - "C:/path/to/source/file1.txt"
  
  # Using glob pattern to copy multiple files
  - "C:/path/to/source/*.txt"
  
  # Copy with original filename to a subdirectory
  - source: "C:/path/to/source/file1.txt"
    directory: "docs"
    
  # Using glob pattern with directory
  - source: "C:/path/to/source/test_*.txt"
    directory: "test_files"
  
  # Copy with original filename to a subdirectory with placeholder
  - source: "C:/path/to/source/file1.txt"
    directory: "{{ environment }}/docs"
  
  # Copy with renaming
  - source: "C:/path/to/source/file2.txt"
    target: "renamed_file2.txt"
  
  # Copy with placeholders in target name
  - source: "C:/path/to/source/config.ini"
    target: "{{ environment }}_config.ini"
  
  # Copy to subfolder
  - source: "C:/path/to/source/data.csv"
    target: "data/{{ date }}_data.csv"
  
  # Copy with nested JSON placeholders
  - source: "C:/path/to/source/file2.txt"
    target: "users/{{ user.name }}_file.txt"
  
  # Copy with deeply nested JSON placeholders
  - source: "C:/path/to/source/config.ini"
    target: "db/{{ database.host }}/{{ database.credentials.username }}_config.ini"
  
  # Create empty folder with nested JSON placeholder
  - target: "logs/{{ user.role }}"
  
  # Create empty folder (simple)
  - target: "temp"

templates:
  # Template with inline content
  - content: |
      # Generated Configuration
      # Generated on: {{ date }}
      
      [Application]
      Name = {{ project_name }}
      Environment = {{ environment }}
      
      [User]
      Name = {{ user.name }}
      Role = {{ user.role }}
    target: "config/generated_config.ini"
  
  # Template from external file
  - file: "C:/path/to/templates/report_template.txt"
    target: "reports/{{ date }}_report.txt"
  
  # Template with Jinja2 conditionals
  - content: |
      <!DOCTYPE html>
      <html>
      <head>
          <title>{{ project_name }} - Environment Info</title>
      </head>
      <body>
          <h1>Environment Information</h1>
          
          {% if environment == 'production' %}
          <p class="warning">This is a PRODUCTION environment. Be careful!</p>
          {% else %}
          <p>This is a {{ environment }} environment.</p>
          {% endif %}
          
          <h2>Database Information</h2>
          <ul>
          {% for key, value in database.items() if key != 'credentials' %}
              <li>{{ key }}: {{ value }}</li>
          {% endfor %}
          </ul>
      </body>
      </html>
    target: "docs/environment.html"

Example Values (example_values.json)

{
    "project_name": "MyProject",
    "environment": "production",
    "date": "2025-11-08",
    "user": {
        "name": "JohnDoe",
        "role": "admin"
    },
    "database": {
        "host": "db.example.com",
        "port": 5432,
        "credentials": {
            "username": "dbuser",
            "password": "secret"
        }
    }
}

Running the Example

# If installed as a package
deployfolder example_config.yaml --values example_values.json

# Or using the module directly
python -m deployfolder example_config.yaml --values example_values.json

This will create:

  • A folder named "MyProject_deploy"
  • Files copied and renamed according to the configuration
  • Empty folders as specified
  • Generated files from templates (config file, report, HTML document)
  • A zip file of the entire folder

Error Handling

The tool provides error messages for common issues:

  • Missing or invalid configuration file
  • Missing or invalid values file
  • File not found errors
  • Permission errors

Testing

The project includes comprehensive unit tests to ensure all functionality works correctly. The tests are implemented using Python's built-in unittest framework.

Running the Tests

To run all the unit tests:

# Run all tests
python -m unittest discover -s tests

# Run a specific test file
python -m unittest tests/test_main.py

# Run the nested JSON test script
python -m tests.test_nested_json

Adding New Tests

To add new tests, extend the existing test classes in tests/test_main.py or create new test classes that inherit from unittest.TestCase. Follow the existing patterns for setting up test fixtures and cleaning up after tests.

License

This project is open source and available under the MIT License.

Copyright (c) 2025 Janosch Meyer (janosch.code@proton.me)

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

Note: This project was created with the assistance of artificial intelligence.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

deployfolder-0.2.0.tar.gz (20.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

deployfolder-0.2.0-py3-none-any.whl (12.8 kB view details)

Uploaded Python 3

File details

Details for the file deployfolder-0.2.0.tar.gz.

File metadata

  • Download URL: deployfolder-0.2.0.tar.gz
  • Upload date:
  • Size: 20.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for deployfolder-0.2.0.tar.gz
Algorithm Hash digest
SHA256 d8bef9ab0ab62cb8939994d45048c0e7210f30dc2ecb6d4d01d4edc7958ef0c5
MD5 c71c129c3ccc4dc63e57bb3f2c96c8d6
BLAKE2b-256 057a62eb50307707ebbcf66b74c8b07a8b1ef72ef35602b48e026b5d2a32eb1b

See more details on using hashes here.

File details

Details for the file deployfolder-0.2.0-py3-none-any.whl.

File metadata

  • Download URL: deployfolder-0.2.0-py3-none-any.whl
  • Upload date:
  • Size: 12.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.2

File hashes

Hashes for deployfolder-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 990e0f740ff8fd20963606bb424fbfc6285ba542d2b236c5ddd0c8b90c587e72
MD5 64348606a0e068482d2f1563331aa524
BLAKE2b-256 f7e76843655213a355959249fc8d092f85eea943550c5008fc8000cd9b7f1eaa

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page