Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/dev-lead.yml
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,12 @@ jobs:
if: env.INTENT_TYPE != 'skip'
run: bash scripts/dev-lead-preflight.sh

- name: Configure git identity
if: env.INTENT_TYPE != 'skip'
run: |
git config --global user.email "donpetry-bot@users.noreply.github.com"
git config --global user.name "donpetry-bot"

# ── Install engine CLIs ───────────────────────────────────────────────
- name: Cache claude-code CLI
if: env.INTENT_TYPE != 'skip'
Expand Down
11 changes: 9 additions & 2 deletions scripts/dev-lead-fix-reviews.sh
Original file line number Diff line number Diff line change
Expand Up @@ -120,9 +120,16 @@ commit_and_push() {
else
if $has_uncommitted; then
git add -A
git commit -m "$commit_msg"
# Explicit exit on failure: set -e is suspended when commit_and_push is called from
# an if-statement condition, so git commit failures would be silently swallowed
# otherwise. Using exit (not return) ensures CI fails visibly instead of posting a
# false "Changes committed and pushed" comment.
git commit -m "$commit_msg" || { echo "::error::git commit failed — check git identity configuration on the runner" >&2; exit 1; }
fi
git push
git push || {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The commit_and_push function is called from an if condition, which suspends set -e. While you've added error handling for git commit, the git push command on this line lacks similar protection. If git push fails (e.g., due to branch protection rules or network issues), the failure will be silently ignored, and the function will still return a success code. This could lead to the script falsely reporting that changes were pushed.

To ensure robustness, you should add explicit error handling for git push.

Suggested change
git push || {
git push || { echo "::error::git push failed" >&2; exit 1; }
References
  1. Keep error routing logic inline to avoid obscuring intent or introducing false positives.

echo "::error::git push failed — check remote access and branch permissions" >&2
exit 1
}
fi
return 0
}
Expand Down
2 changes: 1 addition & 1 deletion scripts/engine.sh
Original file line number Diff line number Diff line change
Expand Up @@ -401,7 +401,7 @@ run_writer() {
timeout "$ACTION_TIMEOUT_SEC" claude --print \
--model "$model" \
--permission-mode acceptEdits \
--allowed-tools "Bash,Read,Write,Edit,Grep,Glob" \
--allowed-tools "Bash,Read,Write,Edit,Grep,Glob,WebFetch" \
< "$prompt_file" | tee "$_tmp" || rc=${PIPESTATUS[0]}
;;
gemini)
Expand Down
121 changes: 121 additions & 0 deletions tests/dev-lead/unit/test_fix_reviews.bats
Original file line number Diff line number Diff line change
Expand Up @@ -363,3 +363,124 @@ STUB
# In dry-run mode, the terminal marker post is announced
[[ "$output" == *"terminal marker"* || "$output" == *"[dry-run]"* ]]
}

# ── commit_and_push failure tests ─────────────────────────────────────────────

@test "fix-reviews: commit_and_push: git commit failure exits 1 (not silently swallowed)" {

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

There is significant code duplication between the two new tests. Much of the setup code (environment variables, temporary git repository creation, claude stub) is identical in @test "fix-reviews: commit_and_push: git commit failure exits 1 (not silently swallowed)" and @test "fix-reviews: commit_and_push: no false 'applied' marker posted on git commit failure".

To improve maintainability and readability, consider refactoring the common setup logic into a helper function. This would make the tests more concise and easier to manage in the future.

export INTENT_TYPE="human"
export DEV_LEAD_DRY_RUN="false"
export HEAD_SHA="abc123"
export ACTOR="donpetry"
export USER_INSTRUCTION="fix something"
# Use absolute path so envsubst can find the prompt even when running from git_repo dir
export PROMPTS_DIR="$SCRIPT_DIR/prompts/dev-lead"

# Real temp git repo with one uncommitted change to trigger commit_and_push
local git_repo
git_repo="$(mktemp -d)"
git -C "$git_repo" init -q
echo "initial" > "$git_repo/file.txt"
git -C "$git_repo" add .
git -C "$git_repo" -c user.email="init@test" -c user.name="Init" commit -q -m "initial"
echo "change" >> "$git_repo/file.txt"

cat > "$STUB_BIN_DIR/claude" << 'STUB'
#!/usr/bin/env bash
echo "Changes applied."
STUB
chmod +x "$STUB_BIN_DIR/claude"

cat > "$STUB_BIN_DIR/gh" << 'GHEOF'
#!/usr/bin/env bash
ARGS="$*"
case "$ARGS" in
*"pr checkout"*) exit 0 ;;
*"pr comment"*) echo "COMMENT_POSTED"; exit 0 ;;
*"pulls/"*) echo '{"head":{"sha":"abc123"}}' ;;
*) echo "{}" ;;
esac
GHEOF
chmod +x "$STUB_BIN_DIR/gh"

# Stub git to fail on commit (simulates missing identity) but pass everything else to real git
cat > "$STUB_BIN_DIR/git" << 'GITEOF'
#!/usr/bin/env bash
if [[ "$*" == *"commit"* ]]; then
echo "::error::git commit failed — check git identity configuration on the runner"
echo "fatal: empty ident name not allowed" >&2
exit 128
fi
exec /usr/bin/git "$@"
GITEOF
chmod +x "$STUB_BIN_DIR/git"

# Run from git_repo so git status/add/commit/push operate on the temp repo
cd "$git_repo"
# Capture stderr too so ::error:: messages appear in $output
run bash "$FIX_REVIEWS_SCRIPT" 2>&1

# Must exit non-zero — git commit failure must NOT be silently swallowed
[ "$status" -ne 0 ]
[[ "$output" == *"error"* || "$output" == *"failed"* || "$output" == *"fatal"* ]]
}

@test "fix-reviews: commit_and_push: no false 'applied' marker posted on git commit failure" {
export INTENT_TYPE="human"
export DEV_LEAD_DRY_RUN="false"
export HEAD_SHA="abc123"
export ACTOR="donpetry"
export USER_INSTRUCTION="fix something"
export PROMPTS_DIR="$SCRIPT_DIR/prompts/dev-lead"

local git_repo
git_repo="$(mktemp -d)"
git -C "$git_repo" init -q
echo "initial" > "$git_repo/file.txt"
git -C "$git_repo" add .
git -C "$git_repo" -c user.email="init@test" -c user.name="Init" commit -q -m "initial"
echo "change" >> "$git_repo/file.txt"

local comment_file
comment_file="$(mktemp)"

cat > "$STUB_BIN_DIR/claude" << 'STUB'
#!/usr/bin/env bash
echo "Changes applied."
STUB
chmod +x "$STUB_BIN_DIR/claude"

cat > "$STUB_BIN_DIR/gh" << GHEOF
#!/usr/bin/env bash
ARGS="\$*"
case "\$ARGS" in
*"pr checkout"*) exit 0 ;;
*"pr comment"*)
echo "\$*" >> "$comment_file"
exit 0 ;;
*"pulls/"*) echo '{"head":{"sha":"abc123"}}' ;;
*) echo "{}" ;;
esac
GHEOF
chmod +x "$STUB_BIN_DIR/gh"

cat > "$STUB_BIN_DIR/git" << 'GITEOF'
#!/usr/bin/env bash
if [[ "$*" == *"commit"* ]]; then
echo "::error::git commit failed — check git identity configuration on the runner"
exit 128
fi
exec /usr/bin/git "$@"
GITEOF
chmod +x "$STUB_BIN_DIR/git"

cd "$git_repo"
run bash "$FIX_REVIEWS_SCRIPT" 2>&1

# Script must exit non-zero when commit fails
[ "$status" -ne 0 ]
# The "applied" status must NOT have been posted since commit failed
if [ -f "$comment_file" ]; then
! grep -q "status=applied" "$comment_file"
fi
rm -f "$comment_file"
Comment thread
coderabbitai[bot] marked this conversation as resolved.
}
Loading