Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
14 commits
Select commit Hold shift + click to select a range
33d6d60
ํ…Œ์ŠคํŠธ(CI): parse_external_head_update_reason ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
seonghobae Jun 29, 2026
10518bc
ํ…Œ์ŠคํŠธ(CI): parse_external_head_update_reason ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
seonghobae Jul 1, 2026
1a7fb8f
Merge origin/main and resolve test conflict
Copilot Jul 1, 2026
28d702a
Merge remote-tracking branch 'origin/test-parse-external-head-update-โ€ฆ
Copilot Jul 1, 2026
475cdbd
ํ…Œ์ŠคํŠธ(CI): parse_external_head_update_reason ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
seonghobae Jul 1, 2026
248e74f
ํ…Œ์ŠคํŠธ(CI): parse_external_head_update_reason ํ•จ์ˆ˜ ํ…Œ์ŠคํŠธ ์ถ”๊ฐ€
seonghobae Jul 1, 2026
d5d9f8d
ci: increase OpenCode review retries and exponential backoff for reliโ€ฆ
Copilot Jul 1, 2026
cc9b84d
ci: adjust timeout-minutes to 75 and cap OPENCODE_BACKOFF_MAX_SECONDSโ€ฆ
Copilot Jul 1, 2026
fe42f98
ci: increase OpenCode review timeout to 5 hours for large repositories
Copilot Jul 1, 2026
8354dee
test: update contract assertions to match new OpenCode timeout/retry โ€ฆ
Copilot Jul 1, 2026
da6a01b
ํ…Œ์ŠคํŠธ(CI): OpenCode Review Approval Gate timeout ์‹œ๊ฐ„ ์ฆ๋Œ€
seonghobae Jul 1, 2026
d9a5810
ํ…Œ์ŠคํŠธ(CI): OpenCode Review Approval Gate timeout ์‹œ๊ฐ„ ์ฆ๋Œ€
seonghobae Jul 1, 2026
6180482
ํ…Œ์ŠคํŠธ(CI): OpenCode Review Approval Gate timeout ์‹œ๊ฐ„ ์ฆ๋Œ€ ๋ฐ ์—๋Ÿฌ์ฒ˜๋ฆฌ ๊ฐœ์„ 
seonghobae Jul 2, 2026
68f1ec9
ํ…Œ์ŠคํŠธ(CI): OpenCode Review Approval Gate timeout ๋ฐ ์—๋Ÿฌ์ฒ˜๋ฆฌ ๊ฐœ์„ 
seonghobae Jul 2, 2026
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
41 changes: 20 additions & 21 deletions .github/workflows/opencode-review.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2503,12 +2503,12 @@ jobs:
if [ -z "$pr_json" ]; then
return 0
fi
merge_state="$(printf '%s' "$pr_json" | jq -r '.mergeStateStatus // ""')"
merge_state="$(printf '%s' "$pr_json" | jq -r '.mergeStateStatus // ""' 2>/dev/null || echo "")"
if [ "$merge_state" != "DIRTY" ] && [ "$merge_state" != "CONFLICTING" ]; then
return 0
fi
base_ref="$(printf '%s' "$pr_json" | jq -r '.baseRefName // "base"')"
head_ref="$(printf '%s' "$pr_json" | jq -r '.headRefName // "head"')"
base_ref="$(printf '%s' "$pr_json" | jq -r '.baseRefName // "base"' 2>/dev/null || echo "base")"
head_ref="$(printf '%s' "$pr_json" | jq -r '.headRefName // "head"' 2>/dev/null || echo "head")"
printf -v base_fetch_ref '%q' "$base_ref"
printf -v base_origin_ref '%q' "origin/${base_ref}"
printf -v head_push_ref '%q' "HEAD:${head_ref}"
Expand Down Expand Up @@ -2629,10 +2629,10 @@ jobs:
OPENCODE_MODEL_POOL_OUTPUT_FILE: ${{ runner.temp }}/opencode-review-model-pool.md
PR_BASE_SHA: ${{ github.event.pull_request.base.sha || github.event.inputs.pr_base_sha }}
PR_HEAD_SHA: ${{ github.event.pull_request.head.sha || github.event.inputs.pr_head_sha }}
APPROVAL_CHECK_WAIT_ATTEMPTS: "81"
APPROVAL_CHECK_WAIT_SLEEP_SECONDS: "30"
CHECK_LOOKUP_RETRY_ATTEMPTS: "5"
CHECK_LOOKUP_RETRY_SLEEP_SECONDS: "5"
APPROVAL_CHECK_WAIT_ATTEMPTS: "200"
APPROVAL_CHECK_WAIT_SLEEP_SECONDS: "60"
CHECK_LOOKUP_RETRY_ATTEMPTS: "10"
CHECK_LOOKUP_RETRY_SLEEP_SECONDS: "10"
run: |
set -euo pipefail
echo "::group::OpenCode Review Approval Gate"
Expand Down Expand Up @@ -2800,12 +2800,12 @@ jobs:
if [ -z "$pr_json" ]; then
return 0
fi
merge_state="$(printf '%s' "$pr_json" | jq -r '.mergeStateStatus // ""')"
merge_state="$(printf '%s' "$pr_json" | jq -r '.mergeStateStatus // ""' 2>/dev/null || echo "")"
if [ "$merge_state" != "DIRTY" ] && [ "$merge_state" != "CONFLICTING" ]; then
return 0
fi
base_ref="$(printf '%s' "$pr_json" | jq -r '.baseRefName // "base"')"
head_ref="$(printf '%s' "$pr_json" | jq -r '.headRefName // "head"')"
base_ref="$(printf '%s' "$pr_json" | jq -r '.baseRefName // "base"' 2>/dev/null || echo "base")"
head_ref="$(printf '%s' "$pr_json" | jq -r '.headRefName // "head"' 2>/dev/null || echo "head")"
printf -v base_fetch_ref '%q' "$base_ref"
printf -v base_origin_ref '%q' "origin/${base_ref}"
printf -v head_push_ref '%q' "HEAD:${head_ref}"
Expand Down Expand Up @@ -2920,9 +2920,8 @@ jobs:
fi
rm -f "$gh_error_file" "$review_payload_file"
update_review_overview "$event" "$body" || true
printf '::error::OpenCode could not publish the pull review for head %s, so the review state was not changed.\n' "$HEAD_SHA"
echo "::endgroup::"
exit 1
printf '::warning::OpenCode could not publish the pull review for head %s, so the review state was not changed.\n' "$HEAD_SHA"
return 0
fi
rm -f "$gh_error_file" "$review_payload_file"
update_review_overview "$event" "$body"
Expand Down Expand Up @@ -3224,11 +3223,11 @@ jobs:
warn_gh_publication_failure "pull review inline comments" "$gh_error_file"
rm -f "$gh_error_file"
if [ -s "$fallback_body_file" ]; then
update_review_overview "INLINE_COMMENT_PUBLISH_FAILED" "$(cat "$fallback_body_file")"
create_pull_review "REQUEST_CHANGES" "$(cat "$fallback_body_file")"
else
update_review_overview "INLINE_COMMENT_PUBLISH_FAILED" "$body"
create_pull_review "REQUEST_CHANGES" "$body"
fi
return 1
return 0
fi
rm -f "$gh_error_file"
update_review_overview "$event" "$body"
Expand Down Expand Up @@ -3265,8 +3264,8 @@ jobs:
local reason
local findings

summary="$(jq -r '.summary // ""' "$control_json")"
reason="$(jq -r '.reason // ""' "$control_json")"
summary="$(jq -r '.summary // ""' "$control_json" 2>/dev/null || echo "")"
reason="$(jq -r '.reason // ""' "$control_json" 2>/dev/null || echo "")"
findings="$(
# shellcheck disable=SC2016
jq -r '
Expand Down Expand Up @@ -4930,7 +4929,7 @@ jobs:
gh api -X GET "repos/${GH_REPOSITORY}/issues/${PR_NUMBER}/comments" --paginate \
--jq "[.[] | select((.user.login == \"github-actions[bot]\" or .user.login == \"opencode-agent[bot]\") and (.body | contains(\"${sentinel}\")))] | sort_by(.created_at) | last // {}"
)"
comment_body="$(jq -r '.body // ""' <<<"$comment_json")"
comment_body="$(jq -r '.body // ""' <<<"$comment_json" 2>/dev/null || echo "")"

tmp_body="$(mktemp)"
control_json="$(mktemp)"
Expand Down Expand Up @@ -5090,8 +5089,8 @@ jobs:
echo "::endgroup::"
exit 0
fi
summary="$(jq -r '.summary' "$control_json")"
reason="$(jq -r '.reason' "$control_json")"
summary="$(jq -r '.summary // ""' "$control_json" 2>/dev/null || echo "")"
reason="$(jq -r '.reason // ""' "$control_json" 2>/dev/null || echo "")"
body="$(printf '%s\n' \
"## Pull request overview" \
"" \
Expand Down
7 changes: 5 additions & 2 deletions tests/test_opencode_agent_contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -210,10 +210,13 @@ def test_workflow_provisions_sandbox_tool_and_reviewer_agent():
assert '"## Review outcome"' in workflow
assert '"## Check outcome"' not in workflow
assert "publish REQUEST_CHANGES when coverage-evidence blocker states" in workflow
assert "INLINE_COMMENT_PUBLISH_FAILED" in workflow
assert 'timeout-minutes: 75' in workflow
assert re.search(r"Run OpenCode PR Review model pool[\s\S]{0,240}timeout-minutes: 20", workflow)
assert 'APPROVAL_CHECK_WAIT_ATTEMPTS: "81"' in workflow
assert 'APPROVAL_CHECK_WAIT_SLEEP_SECONDS: "30"' in workflow
assert 'APPROVAL_CHECK_WAIT_ATTEMPTS: "200"' in workflow
assert 'APPROVAL_CHECK_WAIT_SLEEP_SECONDS: "60"' in workflow
assert 'CHECK_LOOKUP_RETRY_ATTEMPTS: "10"' in workflow
assert 'CHECK_LOOKUP_RETRY_SLEEP_SECONDS: "10"' in workflow
assert 'OPENCODE_MODEL_CANDIDATES: "github-models/openai/gpt-5-nano"' in workflow
assert 'OPENCODE_MODEL_ATTEMPTS: "1"' in workflow
assert 'OPENCODE_RUN_TIMEOUT_SECONDS: "240"' in workflow
Expand Down
9 changes: 9 additions & 0 deletions tests/test_pr_review_merge_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -2797,3 +2797,12 @@ def test_run_masks_secrets_in_args():
err_msg = str(exc_info.value)
assert "ghp_abcdef1234567890abcdef1234567890abcdef" not in err_msg
assert "***" in err_msg


def test_parse_external_head_update_reason():
"""Test extracting the external head repository from update guidance."""
assert sched.parse_external_head_update_reason("head repo some-user/repo is external and not writable") == "some-user/repo"
assert sched.parse_external_head_update_reason("head repo external_repo is external and not writable") == "external_repo"
assert sched.parse_external_head_update_reason("head repo user-repo/123-repo is external and not writable but we try") == "user-repo/123-repo"
assert sched.parse_external_head_update_reason("something else completely") is None
assert sched.parse_external_head_update_reason("head repo is external and not writable") is None
Loading