File Actions¶
File actions provide comprehensive file manipulation capabilities including copying, moving, deleting, appending, and writing files with support for glob patterns and multiple encoding options.
Configuration¶
[[actions]]
name = "action-name"
type = "file"
command = "copy|move|rename|delete|append|write"
# Command-specific fields documented below
Commands¶
copy¶
Copy files or directories with glob pattern support.
Required Fields:
source
: Source file/directory path or glob patterndestination
: Destination path
Examples:
# Copy single file
[[actions]]
name = "copy-readme"
type = "file"
command = "copy"
source = "workflow:///README.md"
destination = "repository:///README.md"
# Copy with glob pattern
[[actions]]
name = "copy-yaml-files"
type = "file"
command = "copy"
source = "workflow:///configs/*.yaml"
destination = "repository:///config/"
# Copy directory
[[actions]]
name = "copy-templates"
type = "file"
command = "copy"
source = "workflow:///templates/"
destination = "repository:///.github/templates/"
# Recursive glob pattern
[[actions]]
name = "copy-all-python"
type = "file"
command = "copy"
source = "workflow:///**/*.py"
destination = "repository:///scripts/"
Glob Pattern Support:
*
- Matches any characters within a filename?
- Matches single character[...]
- Matches character ranges**/
- Recursive directory matching
Behavior:
- Creates destination parent directories automatically
- For glob patterns, destination must be a directory
- Preserves file metadata (timestamps, permissions)
- For directories, uses recursive copy
move¶
Move (rename across directories) files or directories.
Required Fields:
source
: Source file/directory pathdestination
: Destination path
Examples:
# Move file to different directory
[[actions]]
name = "relocate-config"
type = "file"
command = "move"
source = "repository:///old-location/config.yaml"
destination = "repository:///config/app.yaml"
# Reorganize directory structure
[[actions]]
name = "move-tests"
type = "file"
command = "move"
source = "repository:///old_tests/"
destination = "repository:///tests/"
Behavior:
- Source file/directory is removed after move
- Creates destination parent directories automatically
- Fails if source doesn't exist
rename¶
Rename files within the same directory or move to different location.
Required Fields:
source
: Source file pathdestination
: Destination file path
Examples:
# Simple rename
[[actions]]
name = "rename-config"
type = "file"
command = "rename"
source = "repository:///config.yml"
destination = "repository:///config.yaml"
# Rename with path change
[[actions]]
name = "rename-and-move"
type = "file"
command = "rename"
source = "repository:///src/old_module.py"
destination = "repository:///src/new_module.py"
Behavior:
- Similar to
move
but semantically for file renaming - Creates destination parent directories automatically
delete¶
Delete files or directories, with regex pattern matching support.
Required Fields: One of:
path
: Specific file/directory pathpattern
: Regex pattern for matching files
Examples:
# Delete specific file
[[actions]]
name = "remove-old-config"
type = "file"
command = "delete"
path = "repository:///old-config.yaml"
# Delete directory
[[actions]]
name = "remove-cache"
type = "file"
command = "delete"
path = "repository:///__pycache__/"
# Delete with regex pattern
[[actions]]
name = "remove-pyc-files"
type = "file"
command = "delete"
pattern = ".*\\.pyc$"
# Delete temporary files
[[actions]]
name = "cleanup-temps"
type = "file"
command = "delete"
pattern = ".*\\.(tmp|bak|swp)$"
Behavior:
- For
path
: Deletes specific file or directory (recursive) - For
pattern
: Searches recursively and deletes all matching files - Does not error if path doesn't exist
- Pattern matching uses Python regex syntax (string in TOML, compiled at runtime)
append¶
Append content to existing files or create new files.
Required Fields:
path
: Target file pathcontent
: Content to append (string or bytes)
Optional Fields:
encoding
: Character encoding (default:utf-8
)
Examples:
# Append text to existing file
[[actions]]
name = "add-to-gitignore"
type = "file"
command = "append"
path = "repository:///.gitignore"
content = """
# Added by automation
*.log
__pycache__/
.env
"""
# Create or append to file
[[actions]]
name = "add-config-section"
type = "file"
command = "append"
path = "repository:///config.ini"
content = """
[new_section]
option = value
"""
# Append with custom encoding
[[actions]]
name = "append-unicode"
type = "file"
command = "append"
path = "repository:///unicode.txt"
content = "Hello 世界\n"
encoding = "utf-16"
Behavior:
- Creates file if it doesn't exist
- Creates parent directories automatically
- Appends to end of existing files
- Text mode only (bytes are decoded using specified encoding)
write¶
Write content to files, overwriting if they exist.
Required Fields:
path
: Target file pathcontent
: Content to write (string or bytes)
Optional Fields:
encoding
: Character encoding (default:utf-8
)
Examples:
# Write text file
[[actions]]
name = "create-readme"
type = "file"
command = "write"
path = "repository:///README.md"
content = """
# My Project
Description here
## Installation
````bash
pip install my-project
````
"""
# Write JSON configuration
[[actions]]
name = "write-config"
type = "file"
command = "write"
path = "repository:///config.json"
content = """
{
"name": "my-project",
"version": "1.0.0",
"type": "library"
}
"""
# Write with custom encoding
[[actions]]
name = "write-utf16"
type = "file"
command = "write"
path = "repository:///data.txt"
content = "Unicode content: 你好"
encoding = "utf-16"
Behavior:
- Overwrites existing files
- Creates file if it doesn't exist
- Creates parent directories automatically
- Text mode (string) or binary mode (bytes) - detected automatically
- Does NOT support Jinja2 templating (use
template
action instead)
Path Resolution¶
File actions support all ResourceUrl schemes:
Scheme | Base Directory | Use Case |
---|---|---|
file:/// or no scheme |
Working directory | Temporary files |
repository:/// |
Cloned repository | Repository files |
workflow:/// |
Workflow resources | Template files |
extracted:/// |
Docker extracts | Extracted files |
Examples:
# Repository to repository
[[actions]]
type = "file"
command = "copy"
source = "repository:///README.md"
destination = "repository:///docs/README.md"
# Workflow to repository
[[actions]]
type = "file"
command = "copy"
source = "workflow:///templates/.gitignore"
destination = "repository:///.gitignore"
# Extracted to repository
[[actions]]
type = "file"
command = "copy"
source = "extracted:///configs/app.yaml"
destination = "repository:///config/app.yaml"
# Simple paths (relative to working directory)
[[actions]]
type = "file"
command = "write"
path = "temp-file.txt" # Same as file:///temp-file.txt
content = "temporary data"
Common Patterns¶
Backup and Replace Pattern¶
[[actions]]
name = "backup-original"
type = "file"
command = "copy"
source = "repository:///config.yaml"
destination = "repository:///config.yaml.bak"
[[actions]]
name = "write-new-config"
type = "file"
command = "write"
path = "repository:///config.yaml"
content = """
database:
host: localhost
port: 5432
"""
Template Deployment Pattern¶
[[actions]]
name = "copy-gitignore"
type = "file"
command = "copy"
source = "workflow:///.gitignore"
destination = "repository:///.gitignore"
[[actions]]
name = "copy-pre-commit"
type = "file"
command = "copy"
source = "workflow:///.pre-commit-config.yaml"
destination = "repository:///.pre-commit-config.yaml"
Cleanup Pattern¶
[[actions]]
name = "remove-legacy-configs"
type = "file"
command = "delete"
pattern = ".*\\.legacy\\.yaml$"
[[actions]]
name = "remove-cache-dirs"
type = "file"
command = "delete"
path = "repository:///__pycache__/"
Glob Copy Pattern¶
[[actions]]
name = "copy-all-workflows"
type = "file"
command = "copy"
source = "workflow:///.github/workflows/*.yml"
destination = "repository:///.github/workflows/"
[[actions]]
name = "copy-python-modules"
type = "file"
command = "copy"
source = "workflow:///src/**/*.py"
destination = "repository:///src/"
Error Handling¶
File actions raise RuntimeError
in these situations:
copy
/move
/rename
: Source file doesn't existdelete
: No errors (gracefully handles missing files)append
/write
: I/O errors, permission denied
Implementation Notes¶
- All operations create parent directories automatically
- File metadata (permissions, timestamps) preserved in copy operations via
shutil.copy2
- Glob patterns resolved relative to source base directory
- Empty glob results raise
RuntimeError
- Binary content detected automatically (bytes vs string) in
write
command append
command converts bytes to text using encoding (text mode only)- Encoding applies only to text operations (default:
utf-8
) - Pattern field accepts regex strings in TOML, compiled to
re.Pattern
at runtime - Content does NOT support Jinja2 templating - use
template
action type for that