-
Notifications
You must be signed in to change notification settings - Fork 125
Description
Summary
The copilot-setup-steps.yml workflow uses find .github/skills -name pyproject.toml -execdir uv sync \; to install Python dependencies for skills. GNU find does not propagate exit codes from -execdir commands — if uv sync fails for any pyproject.toml, find still returns exit code 0. This means broken or misconfigured Python skill dependencies will silently fail to install. The Copilot coding agent will then encounter runtime ImportError or ModuleNotFoundError with no prior indication of failure in the setup step output.
Additionally, the workflow's find command is missing the -type f flag that the devcontainer includes, which could cause unexpected behavior if a directory happened to match the -name pyproject.toml pattern.
Context
PR #921 added uv installation and skill dependency sync to copilot-setup-steps.yml, implementing the find -execdir pattern prescribed by issue #888. The pattern itself works correctly when all uv sync invocations succeed. The problem is exclusively about failure detection — there is no mechanism to surface or propagate uv sync failures.
Confirmed Behavior: find -execdir Does Not Propagate Exit Codes
This was verified via direct testing on GNU find (Ubuntu/WSL):
$ mkdir -p /tmp/test/a /tmp/test/b
$ touch /tmp/test/a/pyproject.toml /tmp/test/b/pyproject.toml
$ find /tmp/test -name pyproject.toml -execdir false \;
$ echo $?
0Even though false always returns exit code 1, find returns 0. This is documented GNU find behavior — the exit code of find reflects whether find itself completed its traversal successfully, not whether the executed commands succeeded.
The GitHub Actions shell default (bash --noprofile --norc -eo pipefail) means set -e is active, but this is irrelevant because find's return code is 0 regardless of -execdir failures. The step will always pass, even when uv sync fails.
Current State vs Devcontainer
Workflow (copilot-setup-steps.yml, line 89):
find .github/skills -name pyproject.toml -execdir uv sync \;Devcontainer (on-create.sh, line 95):
find .github/skills -name pyproject.toml -type f -execdir uv sync \;Note the devcontainer includes -type f to restrict matches to regular files. The workflow omits this flag. While both commands share the same silent-failure behavior with -execdir, the -type f flag should be added for robustness regardless.
Current Impact
None today — zero skills currently have pyproject.toml files. All existing skills under .github/skills/ contain only .md, .ps1, .sh, .psm1, and .Tests.ps1 files. However, issue #868 tracks the first Python skill (PowerPoint automation), and when that or any future Python skill lands, this code path becomes active and the silent failure risk becomes real.
Changes Required
| File | Change |
|---|---|
.github/workflows/copilot-setup-steps.yml |
Replace find -execdir with loop that propagates uv sync exit codes |
.github/workflows/copilot-setup-steps.yml |
Add -type f flag to the find command for robustness |
Recommended Implementation
Replace the single find-execdir line with a loop that captures and propagates failures:
echo "Syncing Python environments for skills..."
failed=0
while IFS= read -r -d '' f; do
dir="$(dirname "$f")"
echo "Installing dependencies in $dir"
if ! (cd "$dir" && uv sync); then
echo "::error::uv sync failed in $dir"
failed=1
fi
done < <(find .github/skills -name pyproject.toml -type f -print0)
if [[ "$failed" -ne 0 ]]; then
echo "::error::One or more skill dependency installations failed"
exit 1
fiThis approach:
- Uses
-print0/read -d ''for safe handling of paths with spaces or special characters - Includes
-type fto match only regular files (parity with devcontainer) - Emits
::error::annotations visible in the GitHub Actions UI per-directory failure - Continues processing remaining skills even when one fails (reports all failures, not just the first)
- Exits with non-zero status if any
uv syncinvocation fails
Alternative: Minimal Fix
If the loop approach is considered too verbose, a simpler alternative adds error propagation to the devcontainer pattern as well:
find .github/skills -name pyproject.toml -type f -print0 | \
xargs -0 -I {} bash -c 'cd "$(dirname "{}")" && uv sync'However, this stops at the first failure and doesn't provide per-directory annotations. The loop approach is preferred.
Devcontainer Consideration
The devcontainer (on-create.sh, line 95) has the same silent-failure bug with -execdir. However, the devcontainer has set -euo pipefail at the top and is used interactively where failures are quickly noticed. A separate fix for on-create.sh may be warranted but is out of scope for this issue.
Acceptance Criteria
-
uv syncfailures produce a non-zero exit code from the install step - Each skill directory with a failed
uv syncproduces a visible::error::annotation in the Actions log - The
-type fflag is present on the find command - All matching
pyproject.tomlfiles are processed even when one fails (no early abort) - Paths with spaces or special characters are handled safely
- The fix is verified by temporarily injecting a broken
pyproject.tomlin a test run (manual verification step)
Related
- feat(ci): Add uv and Python package sync to copilot-setup-steps #888 — Parent issue for PR feat(workflows): add uv and Python package sync to copilot-setup-steps #921 (prescribed the
find -execdirpattern) - feat(skills): add PowerPoint automation skill with YAML-driven deck generation #868 — First Python skill (PowerPoint automation) — will activate this code path when merged
- PR feat(workflows): add uv and Python package sync to copilot-setup-steps #921 — The PR that introduced the
find -execdir uv synccommand to copilot-setup-steps