-
-
Notifications
You must be signed in to change notification settings - Fork 243
Description
Describe the problem
Bug Report: TUI prompts appear during copier update despite --defaults --skip-answered flags
Description
When running copier update with --defaults --skip-answered flags in automation contexts (Make targets, shell scripts), the interactive TUI still appears and prompts for questions that have already been answered. This breaks non-interactive workflows and causes commands to hang waiting for user input.
Expected Behavior
When using --defaults --skip-answered flags, copier should:
- Use default values for all questions
- Skip questions that already have answers in
.copier-answers.yml - Run completely non-interactively without showing the TUI
- Complete successfully without requiring terminal input
Actual Behavior
Despite using --defaults --skip-answered flags, copier:
- Shows the interactive TUI with emoji prompts (π€)
- Displays questions that already have answers
- Waits for user input, causing the command to hang
- Prevents automation/CI/CD workflows from completing
Reproduction Steps
- Create a template and generate a project with copier
- Ensure project has
.copier-answers.ymlwith previous answers - Run update from a Makefile or script using
$()command substitution:update: OUTPUT=$$(copier update --trust --defaults --skip-answered --vcs-ref=HEAD 2>&1); \ echo "$$OUTPUT"
- The command hangs showing interactive prompts despite flags
Environment
- Copier version: 9.11.0
- Python version: 3.12
- OS: Linux
- Context: Make target with
$$()command substitution
Root Cause
Copier detects if stdin is connected to a terminal and launches the TUI even when --defaults --skip-answered flags are present. In Make's $$() subprocess, stdin remains open/connected, causing copier to attempt interactive mode.
Workaround
Close stdin explicitly when running copier in a subshell:
( copier update --trust --defaults --skip-answered --vcs-ref=HEAD 0<&- < /dev/null ) > output.txt 2>&1Or in a Makefile:
OUTPUT=$$($$COPIER_CMD update $$OPTS 0<&- < /dev/null 2>&1);This forces copier into non-interactive mode by closing file descriptor 0.
Impact
This issue affects:
- β Makefile-based automation
- β CI/CD pipelines using shell script wrappers
- β Any subprocess that captures output via
$() - β Automated template updates in frameworks
Suggested Fix
The --defaults and --skip-answered flags should take precedence over stdin detection. If these flags are present, copier should:
- Never attempt to show the TUI
- Raise an error if a required question has no default/answer (as documented)
- Run in truly non-interactive mode regardless of stdin state
Alternatively, document that stdin must be explicitly closed when running copier in subprocess contexts for automation.
References
- Existing issue that added
--skip-answered: Don't require users to review all questions when running copier updateΒ #1178 - Documentation: https://copier.readthedocs.io/en/stable/configuring/#skip_answered
- Test coverage exists but uses
pexpect.spawn()with PTY, not subprocess$()
Additional Context
The extensive test suite for --skip-answered uses spawn() which creates a pseudo-terminal (PTY). This is different from Make's $$() subprocess behavior where stdin is inherited from the parent process. The tests pass because PTY behaves differently than real subprocess stdin redirection.
The workaround is reliable but non-obvious. Many users expect --defaults --skip-answered to mean "never prompt, use existing answers" without needing to understand stdin file descriptor manipulation.
Template
Digitalized Architecture Framework - Template Configuration
=============================================================
_metadata:
version: "1.1.0"
description: "Digitalized Architecture Framework with Four Architecting Pillars"
Default answers (for --defaults mode)
project_name: "my-project"
project_description: "A software development project using the Digitalized Architecture Framework"
organization_name: "Development Team"
methodology_folder: "daf-methodology"
workspace_folder: "daf-workspace"
tests_folder: "tests"
use_capability_areas: true
use_user_journeys: true
use_issue_templates: true
use_test_methodology: true
use_reports: false
Questions for interactive mode
_questions:
project_name:
type: str
help: "What is the name of your project?"
placeholder: "my-awesome-project"
default: "my-project"
project_description:
type: str
help: "Brief description of your project"
placeholder: "An innovative solution for..."
default: "A software development project"
organization_name:
type: str
help: "Your organization name"
placeholder: "Acme Corp"
default: "Development Team"
workspace_folder:
type: str
help: "Name for the workspace folder (your project work)"
placeholder: "daf-workspace, ai-project, my-workspace"
default: "daf-workspace"
tests_folder:
type: str
help: "Name for the tests folder (test suite location)"
placeholder: "tests, test, tst"
default: "tests"
use_capability_areas:
type: bool
help: "Include Capability Area methodology?"
default: true
use_user_journeys:
type: bool
help: "Include User Journey methodology?"
default: true
use_issue_templates:
type: bool
help: "Include issue tracking templates?"
default: true
use_test_methodology:
type: bool
help: "Include testing methodology?"
default: true
use_reports:
type: bool
help: "Include reporting tools and templates?"
default: false
Template processing
_templates_suffix: ".jinja2"
_envops:
keep_trailing_newline: true
Skip existing files by default (non-destructive installation)
_skip_if_exists:
- "README.md"
- "*/README.md"
Files to exclude
_exclude:
- "copier.yml"
- "copier.yml.bak"
- ".copier-answers.yml" # Framework's answers (adopters generate their own)
- ".git"
- ".gitignore"
- "*.pyc"
- "pycache"
- ".DS_Store"
Framework development (not shipped to users)
- "daf-workspace"
- "daf-workspace/**"
- "pytest.ini" # Dev version includes daf-workspace/tests
- "install.sh"
- "pdf"
- "pdf/**"
- "tests"
- "tests/**"
Install scripts and templates (used by install.sh, not copied)
- "daf-methodology/bin/install"
- "daf-methodology/bin/install/**"
Symlinked directories (do not copy symlinks, copy actual source files instead)
- "daf-methodology/docs/_root"
- "daf-methodology/docs/_root/**"
Generated files
- "**/00-OVERVIEW.md" # Generated by navigation script
- "daf-methodology/docs/index.md" # Symlink (generated)
Framework-specific files (not for adopters)
- "mkdocs-ai-dev.yml" # Framework dev only (not copied to adopters)
- "CONTRIBUTING.md" # Copied as DAF-CONTRIBUTING.md by install.sh
Tasks to run after generation
_tasks:
Note: Copier automatically creates .copier-answers.yml for update support
- "echo 'β Digitalized Architecture Framework installed successfully!'"
- "echo ''"
- "echo 'π Framework: 8 Methodologies across 4 Pillars'"
- "echo ' Pillar 1: Value Stream Architecting (User Journey, Domain Modeling)'"
- "echo ' Pillar 2: Complexity Management Architecting (Capability Area, Arc42++)'"
- "echo ' Pillar 3: Product Memory Architecting (Knowledge Map, Conversation Backlog)'"
- "echo ' Pillar 4: Quality Assurance Architecting (Testing Pyramid, Delivery Modeling)'"
- "echo ''"
- "echo 'π What was created:'"
- "echo ' β’ docs/knowledge-map.html - Interactive methodology visualization'"
- "echo ' β’ README.md - Framework overview with Four Pillars'"
- "echo ' β’ daf-methodology/make/backlog.mk - Makefile extension for backlog management'"
- "echo ' β’ daf-methodology/bin/backlog/ - Backlog management scripts (CLI, TUI)'"
- "echo ' β’ .github/instructions/ - AI agent instruction files (context-optimized)'"
- "echo ' β’ .github/prompts/ - README enhancement prompts for AI agents'"
- "echo ' β’ docs/capability-areas/ - Feature development templates'"
- "echo ' β’ docs/user-journeys/ - User experience templates'"
- "echo ' β’ issues/templates/ - Issue tracking templates (Conversation Backlog)'"
- "echo ' β’ tests/ - Testing Pyramid methodology'"
- "{% if use_reports %}echo ' β’ reports/ - Reporting tools'{% endif %}"
- "echo ''"
- "echo 'π Quick Start:'"
- "echo ' 1. Explore: Run make meth-serve (Ctrl+Click URL to open docs)'"
- "echo ' 2. Document: Start in daf-workspace/docs/capability-areas/'"
- "echo ' 3. Issues: Run make issues-ui (interactive TUI)'"
- "echo ''"
- "echo 'βοΈ Optional (custom folder names): Edit daf-config.yml, then run make config-update'"
- "echo 'π¦ Updates: Run make daf-update to get latest framework'"
To Reproduce
No response
Logs
Expected behavior
it should work without TUI
Screenshots/screencasts/logs
No response
Operating system
Linux
Operating system distribution and version
Ubuntu 24
Copier version
Copier 9.11.0
Python version
Python 3.12.3
Installation method
uvx+pypi
Additional context
No response