πŸ“ Template Customization

Customizing Copier templates for project generation.


Template Location

1
2
3
4
5
6
templates/
β”œβ”€β”€ copier.yml           # Main configuration
β”œβ”€β”€ hooks/
β”‚   β”œβ”€β”€ pre_gen.py       # Before generation
β”‚   └── post_gen.py      # After generation
└── {{ project_name }}/  # Template directory

Adding New Questions

Edit copier.yml:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# Add a new question
feature_flags:
  type: bool
  help: Include feature flag support?
  default: false

api_style:
  type: str
  help: API architecture style
  choices:
    - rest
    - graphql
    - grpc
  default: rest

Conditional Files

Use Jinja conditionals in directory names:

1
2
3
4
5
6
7
8
9
{{ project_name }}/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ index.ts.jinja
β”‚   β”œβ”€β”€ {% if api_style == 'graphql' %}
β”‚   β”‚   └── schema.graphql.jinja
β”‚   β”‚   {% endif %}
β”‚   └── {% if feature_flags %}
β”‚       └── flags.ts.jinja
β”‚       {% endif %}

Template Content

Variables

1
2
3
4
5
6
// {{ project_name }}/src/config.ts
export const config = {
  name: '{{ project_name }}',
  owner: '{{ owner }}',
  version: '{{ version | default("1.0.0") }}',
};

Conditionals

1
2
3
4
5
6
7
{% if include_sea_governance %}
import { SeaValidator } from '@sea/validator';

export function validateOnStartup() {
  return SeaValidator.check();
}
{% endif %}

Loops

1
2
3
{% for dep in dependencies %}
import { {{ dep.export }} } from '{{ dep.package }}';
{% endfor %}

Custom Hooks

Pre-Generation Hook

1
2
3
4
5
6
7
8
9
10
11
12
# hooks/pre_gen.py
import os
import sys

def validate_project_name():
    name = os.environ.get('project_name', '')
    if not name.replace('-', '').isalnum():
        print("Error: Project name must be alphanumeric with hyphens")
        sys.exit(1)

if __name__ == '__main__':
    validate_project_name()

Post-Generation Hook

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# hooks/post_gen.py
import subprocess
import os

def install_dependencies():
    os.chdir(os.environ['project_name'])
    subprocess.run(['pnpm', 'install'], check=True)

def setup_git():
    subprocess.run(['git', 'init'], check=True)
    subprocess.run(['git', 'add', '.'], check=True)

if __name__ == '__main__':
    install_dependencies()
    setup_git()
    print("βœ… Project setup complete!")

SEAβ„’ Governance Extension

Add SEA-specific questions:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# SEAβ„’ Governance Questions
include_sea_governance:
  type: bool
  help: Enable SEAβ„’ DSL validation?
  default: true

sea_bounded_context:
  type: str
  help: SEAβ„’ bounded context
  choices:
    - semantic-core
    - cognitive-extension
    - architectural-governance
    - developer-tooling
  default: developer-tooling
  when: '{{ include_sea_governance }}'

include_calm_validation:
  type: bool
  help: Include CALM architecture validation?
  default: true
  when: '{{ include_sea_governance }}'

Testing Templates

1
2
3
4
5
6
7
8
# Test with specific answers
copier copy ./templates ./test-output \
  --data project_name=test-project \
  --data owner=test-team \
  --data include_sea_governance=true

# Compare output
diff -r ./expected ./test-output

Best Practices

  1. Keep templates minimal - Don’t over-engineer
  2. Use sensible defaults - Most users accept defaults
  3. Document questions - Clear help text is essential
  4. Test thoroughly - Test all question combinations
  5. Version templates - Track template changes