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
89 changes: 89 additions & 0 deletions .github/workflows/sdlc-pipeline.yml
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,95 @@ jobs:
echo "Branch ${BRANCH_NAME} already exists"
git checkout "${BRANCH_NAME}"
git pull origin "${BRANCH_NAME}"

# Merge latest main into the issue branch to avoid working on stale code
echo "Merging latest main into ${BRANCH_NAME}..."
git fetch origin main
if ! git merge-base --is-ancestor origin/main HEAD; then
echo "Main has commits not in ${BRANCH_NAME}, merging..."
if git merge origin/main --no-edit; then
echo "Successfully merged main into ${BRANCH_NAME}"
# Push the merge commit so reviewers and subsequent steps see it
git push origin "${BRANCH_NAME}" || {
echo "::warning::Initial push failed, attempting pull --rebase and retry..."
if ! git pull --rebase origin "${BRANCH_NAME}"; then
echo "::error::Failed to rebase during push retry"
exit 1
fi
if ! git push origin "${BRANCH_NAME}"; then
echo "::error::Failed to push after rebase"
exit 1
fi
}
else
echo "::warning::Merge conflict detected, triggering conflict resolution workflow..."
git merge --abort

# Find PR number for this branch
CONFLICT_PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[0].number // empty' || echo "")

if [[ -n "${CONFLICT_PR_NUMBER}" ]]; then
echo "Found PR #${CONFLICT_PR_NUMBER} for branch ${BRANCH_NAME}, triggering conflict resolution..."
# Record timestamp before triggering to avoid race condition with other runs
TRIGGER_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
if gh workflow run on-merge-conflict.yml -f pr_number="${CONFLICT_PR_NUMBER}"; then
echo "::notice::Conflict resolution workflow triggered for PR #${CONFLICT_PR_NUMBER}"

# Wait for conflict resolver to complete
echo "Waiting for conflict resolution workflow to start..."
sleep 10

# Find the triggered workflow run (filter by timestamp to avoid race condition)
CONFLICT_RUN_ID=""
for attempt in 1 2 3 4 5 6; do
CONFLICT_RUN_ID=$(gh run list \
--workflow on-merge-conflict.yml \
--limit 10 \
--json databaseId,status,createdAt \
--jq "[.[] | select(.createdAt > \"${TRIGGER_TIME}\")] | sort_by(.createdAt) | reverse | .[0].databaseId // empty" 2>/dev/null || echo "")
if [[ -n "$CONFLICT_RUN_ID" ]]; then
break
fi
echo "::warning::Attempt ${attempt}: conflict resolution workflow run not found yet, retrying..."
sleep 5
done

if [[ -z "$CONFLICT_RUN_ID" ]]; then
echo "::error::Could not find triggered conflict resolution workflow run (triggered after ${TRIGGER_TIME}). Possible causes: workflow doesn't exist, permissions issue, or GitHub Actions delay."
exit 1
fi

echo "Watching conflict resolution workflow run ${CONFLICT_RUN_ID}..."
if gh run watch "$CONFLICT_RUN_ID" --exit-status; then
echo "Conflict resolution completed successfully"
# Pull the resolved changes with explicit error handling
if ! git fetch origin "${BRANCH_NAME}"; then
echo "::error::Failed to fetch resolved branch"
exit 1
fi
if ! git reset --hard "origin/${BRANCH_NAME}"; then
echo "::error::Failed to reset to resolved branch"
exit 1
fi
echo "Pulled resolved changes, continuing..."
else
echo "::error::Conflict resolution workflow failed (run ${CONFLICT_RUN_ID})"
exit 1
fi
else
echo "::warning::Failed to trigger conflict resolution workflow"
echo "::error::Merge conflict merging main into ${BRANCH_NAME}. Manual resolution required."
exit 1
fi
else
echo "::warning::No PR found for branch ${BRANCH_NAME}, cannot trigger automatic conflict resolution"
echo "::error::Merge conflict merging main into ${BRANCH_NAME}. Manual resolution required."
exit 1
fi
fi
else
echo "Branch already contains latest main, skipping merge"
fi
else
echo "Creating new branch ${BRANCH_NAME}"
git checkout -b "${BRANCH_NAME}"
Expand Down
151 changes: 138 additions & 13 deletions .github/workflows/sdlc-work-loop.yml
Original file line number Diff line number Diff line change
Expand Up @@ -363,12 +363,119 @@ jobs:
git add "$CONTRACT_PATH"
git commit -m "Reset autofix attempts for issue #${ISSUE_NUMBER}" || true
git push origin "${BRANCH_NAME}" || {
git pull --rebase origin "${BRANCH_NAME}"
git push origin "${BRANCH_NAME}"
echo "::warning::Initial push failed, attempting pull --rebase and retry..."
if ! git pull --rebase origin "${BRANCH_NAME}"; then
echo "::error::Failed to rebase during autofix reset push"
exit 1
fi
if ! git push origin "${BRANCH_NAME}"; then
echo "::error::Failed to push autofix reset after rebase"
exit 1
fi
}
fi
fi

- name: Merge latest main into issue branch
env:
GH_TOKEN: ${{ steps.bot-token.outputs.token }}
PR_NUMBER: ${{ needs.resolve-inputs.outputs.pr_number }}
run: |
set -euo pipefail
echo "Merging latest main into ${BRANCH_NAME}..."
git fetch origin main

# Check if merge is needed
if git merge-base --is-ancestor origin/main HEAD; then
echo "Branch already contains latest main, skipping merge"
exit 0
fi

echo "Main has commits not in ${BRANCH_NAME}, merging..."
if git merge origin/main --no-edit; then
echo "Successfully merged main into ${BRANCH_NAME}"
# Push the merge commit so reviewers and subsequent steps see it
git push origin "${BRANCH_NAME}" || {
echo "::warning::Initial push failed, attempting pull --rebase and retry..."
if ! git pull --rebase origin "${BRANCH_NAME}"; then
echo "::error::Failed to rebase during push retry"
exit 1
fi
if ! git push origin "${BRANCH_NAME}"; then
echo "::error::Failed to push after rebase"
exit 1
fi
}
else
echo "::warning::Merge conflict detected, triggering conflict resolution workflow..."
git merge --abort

# Find PR number for this branch if not already known
CONFLICT_PR_NUMBER="${PR_NUMBER}"
if [[ "${CONFLICT_PR_NUMBER}" == "0" || -z "${CONFLICT_PR_NUMBER}" ]]; then
CONFLICT_PR_NUMBER=$(gh pr list --head "${BRANCH_NAME}" --json number --jq '.[0].number // empty' || echo "")
fi

if [[ -n "${CONFLICT_PR_NUMBER}" && "${CONFLICT_PR_NUMBER}" != "0" ]]; then
echo "Found PR #${CONFLICT_PR_NUMBER} for branch ${BRANCH_NAME}, triggering conflict resolution..."
# Record timestamp before triggering to avoid race condition with other runs
TRIGGER_TIME=$(date -u +%Y-%m-%dT%H:%M:%SZ)
if gh workflow run on-merge-conflict.yml -f pr_number="${CONFLICT_PR_NUMBER}"; then
echo "::notice::Conflict resolution workflow triggered for PR #${CONFLICT_PR_NUMBER}"

# Wait for conflict resolver to complete
echo "Waiting for conflict resolution workflow to start..."
sleep 10

# Find the triggered workflow run (filter by timestamp to avoid race condition)
CONFLICT_RUN_ID=""
for attempt in 1 2 3 4 5 6; do
CONFLICT_RUN_ID=$(gh run list \
--workflow on-merge-conflict.yml \
--limit 10 \
--json databaseId,status,createdAt \
--jq "[.[] | select(.createdAt > \"${TRIGGER_TIME}\")] | sort_by(.createdAt) | reverse | .[0].databaseId // empty" 2>/dev/null || echo "")
if [[ -n "$CONFLICT_RUN_ID" ]]; then
break
fi
echo "::warning::Attempt ${attempt}: conflict resolution workflow run not found yet, retrying..."
sleep 5
done

if [[ -z "$CONFLICT_RUN_ID" ]]; then
echo "::error::Could not find triggered conflict resolution workflow run (triggered after ${TRIGGER_TIME}). Possible causes: workflow doesn't exist, permissions issue, or GitHub Actions delay."
exit 1
fi

echo "Watching conflict resolution workflow run ${CONFLICT_RUN_ID}..."
if gh run watch "$CONFLICT_RUN_ID" --exit-status; then
echo "Conflict resolution completed successfully"
# Pull the resolved changes with explicit error handling
if ! git fetch origin "${BRANCH_NAME}"; then
echo "::error::Failed to fetch resolved branch"
exit 1
fi
if ! git reset --hard "origin/${BRANCH_NAME}"; then
echo "::error::Failed to reset to resolved branch"
exit 1
fi
echo "Pulled resolved changes, continuing..."
else
echo "::error::Conflict resolution workflow failed (run ${CONFLICT_RUN_ID})"
exit 1
fi
else
echo "::warning::Failed to trigger conflict resolution workflow"
echo "::error::Merge conflict merging main into ${BRANCH_NAME}. Manual resolution required."
exit 1
fi
else
echo "::warning::No PR found for branch ${BRANCH_NAME}, cannot trigger automatic conflict resolution"
echo "::error::Merge conflict merging main into ${BRANCH_NAME}. Manual resolution required."
exit 1
fi
fi

- name: Populate contract tasks (implement phase only)
if: env.PHASE == 'implement'
env:
Expand All @@ -388,9 +495,15 @@ jobs:
git add "$CONTRACT_PATH"
git commit -m "Populate contract tasks from plan for issue #${ISSUE_NUMBER}"
git push origin "${BRANCH_NAME}" || {
# Handle conflict with retry
git pull --rebase origin "${BRANCH_NAME}"
git push origin "${BRANCH_NAME}"
echo "::warning::Initial push failed, attempting pull --rebase and retry..."
if ! git pull --rebase origin "${BRANCH_NAME}"; then
echo "::error::Failed to rebase during contract push"
exit 1
fi
if ! git push origin "${BRANCH_NAME}"; then
echo "::error::Failed to push contract after rebase"
exit 1
fi
}
fi

Expand Down Expand Up @@ -652,7 +765,9 @@ jobs:
)
runs-on: ubuntu-latest
outputs:
fixed: ${{ steps.fix.outputs.fixed || steps.limit-exceeded.outputs.fixed || 'false' }}
# Only report fixed=true if both the autofix succeeded AND the counter was updated.
# This prevents re-dispatch if the counter update fails.
fixed: ${{ (steps.fix.outputs.fixed == 'true' && steps.update-counter.outputs.counter_updated != 'false') && 'true' || steps.limit-exceeded.outputs.fixed || 'false' }}
limit_exceeded: ${{ steps.check-limit.outputs.exceeded }}

env:
Expand Down Expand Up @@ -688,6 +803,11 @@ jobs:
id: check-limit
run: |
set -euo pipefail

# Fetch latest to get any concurrent updates to autofix_attempts
git fetch origin "${BRANCH_NAME}"
git reset --hard "origin/${BRANCH_NAME}"

CONTRACT_PATH=".egg-state/contracts/${ISSUE_NUMBER}.json"

if [[ -f "$CONTRACT_PATH" ]]; then
Expand Down Expand Up @@ -774,20 +894,20 @@ jobs:
sleep 5

# Find the triggered workflow run
# Filter by: branch name only (not main), status queued/in_progress, created after dispatch
# Filter by: timestamp only (workflow_dispatch doesn't set headBranch to issue branch)
# We use timestamp filtering to identify the run we just triggered
RUN_ID=""
for attempt in 1 2 3 4 5 6; do
RUN_ID=$(gh run list \
--repo "${{ github.repository }}" \
--workflow reusable-autofix.yml \
--limit 10 \
--json databaseId,status,createdAt,headBranch \
--jq --arg branch "${BRANCH_NAME}" --arg dispatch_time "${DISPATCH_TIME}" '
--json databaseId,status,createdAt \
--jq --arg dispatch_time "${DISPATCH_TIME}" '
[.[] | select(
.headBranch == $branch and
(.status == "queued" or .status == "in_progress" or .status == "completed") and
.createdAt >= $dispatch_time
)] | sort_by(.createdAt) | reverse | .[0].databaseId // empty
)] | sort_by(.createdAt) | .[0].databaseId // empty
' 2>/dev/null || echo "")
if [[ -n "$RUN_ID" ]]; then
echo "Found autofix workflow run: ${RUN_ID}"
Expand All @@ -798,7 +918,7 @@ jobs:
done

if [[ -z "$RUN_ID" ]]; then
echo "::warning::Could not find triggered autofix workflow run after 30 seconds"
echo "::warning::Could not find triggered autofix workflow run after 30 seconds (triggered at ${DISPATCH_TIME}). Possible causes: workflow doesn't exist, permissions issue, or GitHub Actions delay."
echo "fixed=false" >> "$GITHUB_OUTPUT"
exit 0
fi
Expand Down Expand Up @@ -827,6 +947,7 @@ jobs:
echo "fixed=false" >> "$GITHUB_OUTPUT"

- name: Update autofix attempts counter
id: update-counter
if: steps.check-limit.outputs.exceeded != 'true'
run: |
set -euo pipefail
Expand Down Expand Up @@ -899,11 +1020,15 @@ jobs:
git commit -m "Update autofix attempts for issue #${ISSUE_NUMBER}" || true
done

# Fail the step if push never succeeded
# Fail the step if push never succeeded - this prevents re-dispatch
if [[ "$PUSH_SUCCEEDED" != "true" ]]; then
echo "::error::Failed to push contract update after 3 attempts"
echo "counter_updated=false" >> "$GITHUB_OUTPUT"
exit 1
fi
echo "counter_updated=true" >> "$GITHUB_OUTPUT"
else
echo "counter_updated=true" >> "$GITHUB_OUTPUT"
fi

# ============================================================
Expand Down
Loading