mirror of
https://github.com/openobserve/openobserve.git
synced 2026-11-05 16:10:43 +00:00
Co-authored-by: Ashish Kolhe <35160958+oasisk@users.noreply.github.com>
342 lines
16 KiB
YAML
342 lines
16 KiB
YAML
name: Playwright Auto-Rerun
|
|
|
|
run-name: "Playwright Auto-Rerun - ${{ github.event.workflow_run.head_branch || 'Manual Trigger' }}"
|
|
|
|
on:
|
|
workflow_run:
|
|
workflows:
|
|
- "Playwright UI Tests"
|
|
- "Playwright Regression Tests"
|
|
types:
|
|
- completed
|
|
branches:
|
|
- main
|
|
- '**' # Also trigger on all branches for testing
|
|
workflow_dispatch:
|
|
inputs:
|
|
run_id:
|
|
description: 'Workflow run ID to rerun (for manual testing)'
|
|
required: true
|
|
type: string
|
|
|
|
jobs:
|
|
auto_rerun_on_failure:
|
|
timeout-minutes: 15
|
|
name: Auto Rerun Failed Jobs
|
|
permissions:
|
|
actions: write
|
|
contents: read
|
|
runs-on: ubuntu-latest
|
|
# Only trigger if the workflow failed on first attempt (for automatic triggers)
|
|
# OR if manually triggered (for testing)
|
|
if: |
|
|
github.event_name == 'workflow_dispatch' ||
|
|
(github.event.workflow_run.conclusion == 'failure' &&
|
|
github.event.workflow_run.run_attempt == 1)
|
|
steps:
|
|
- name: Debug - Print trigger information
|
|
env:
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
WR_ID: ${{ github.event.workflow_run.id }}
|
|
WR_CONCLUSION: ${{ github.event.workflow_run.conclusion }}
|
|
WR_ATTEMPT: ${{ github.event.workflow_run.run_attempt }}
|
|
WR_STATUS: ${{ github.event.workflow_run.status }}
|
|
WR_NAME: ${{ github.event.workflow_run.name }}
|
|
WR_BRANCH: ${{ github.event.workflow_run.head_branch }}
|
|
WR_SHA: ${{ github.event.workflow_run.head_sha }}
|
|
WR_EVENT: ${{ github.event.workflow_run.event }}
|
|
WR_HEAD_REPO: ${{ github.event.workflow_run.head_repository.full_name }}
|
|
INPUT_RUN_ID: ${{ inputs.run_id }}
|
|
run: |
|
|
echo "::group::Trigger Information"
|
|
echo "Event name: $EVENT_NAME"
|
|
echo "Repository: $GITHUB_REPOSITORY"
|
|
|
|
if [ "$EVENT_NAME" = "workflow_run" ]; then
|
|
echo "::notice::🔄 Auto-rerun triggered for branch: $WR_BRANCH"
|
|
echo "Workflow run ID: $WR_ID"
|
|
echo "Workflow run conclusion: $WR_CONCLUSION"
|
|
echo "Workflow run attempt: $WR_ATTEMPT"
|
|
echo "Workflow run status: $WR_STATUS"
|
|
echo "Workflow name: $WR_NAME"
|
|
echo "Branch: $WR_BRANCH"
|
|
echo "Commit: $WR_SHA"
|
|
echo "Event type: $WR_EVENT"
|
|
|
|
# For PR events, extract PR number from head_branch (format: refs/pull/123/merge or branch name)
|
|
if [ "$WR_EVENT" = "pull_request" ]; then
|
|
echo "::notice::📋 Triggered by PR event"
|
|
echo "PR Head Repo: $WR_HEAD_REPO"
|
|
fi
|
|
else
|
|
echo "Manual run_id input: $INPUT_RUN_ID"
|
|
fi
|
|
echo "::endgroup::"
|
|
|
|
- name: Install GitHub CLI
|
|
run: |
|
|
echo "::group::Installing GitHub CLI"
|
|
|
|
# Check if gh is already installed
|
|
if command -v gh &> /dev/null; then
|
|
echo "::notice::GitHub CLI already installed"
|
|
gh --version
|
|
else
|
|
echo "::notice::Installing GitHub CLI..."
|
|
type -p curl >/dev/null || (sudo apt update && sudo apt install curl -y)
|
|
curl -fsSL https://cli.github.com/packages/githubcli-archive-keyring.gpg | sudo dd of=/usr/share/keyrings/githubcli-archive-keyring.gpg
|
|
sudo chmod go+r /usr/share/keyrings/githubcli-archive-keyring.gpg
|
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/githubcli-archive-keyring.gpg] https://cli.github.com/packages stable main" | sudo tee /etc/apt/sources.list.d/github-cli.list > /dev/null
|
|
sudo apt update
|
|
sudo apt install gh -y
|
|
echo "::notice::GitHub CLI installed successfully"
|
|
gh --version
|
|
fi
|
|
|
|
echo "::endgroup::"
|
|
|
|
- name: Check rerun advice
|
|
id: advice
|
|
continue-on-error: true
|
|
env:
|
|
GH_REPO: ${{ github.repository }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
COMMENT_TOKEN: ${{ secrets.ORG_ADMIN_TOKEN }} # PAT: comment as a human, not github-actions[bot]
|
|
OSS_REPO: openobserve/openobserve
|
|
RUN_ID: ${{ github.event.workflow_run.id || inputs.run_id }}
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
PR_NUMBER: ${{ github.event.workflow_run.pull_requests[0].number }}
|
|
PR_BASE: ${{ github.event.workflow_run.pull_requests[0].base.ref }}
|
|
run: |
|
|
MARKER="<!-- playwright-rerun-advice -->"
|
|
if ! RUN=$(gh run view "$RUN_ID" --repo "$GH_REPO" --json name,attempt,event,headSha,headBranch,url); then
|
|
echo "::warning::Could not read run $RUN_ID; rerunning the failed jobs as before."
|
|
exit 0
|
|
fi
|
|
ATTEMPT=$(jq -r '.attempt' <<< "$RUN")
|
|
# A manual start meets attempt 2+ because the automatic path always reruns attempt 1 first.
|
|
if [ "$(jq -r '.name' <<< "$RUN")" != "Playwright UI Tests" ] || ! [[ "$ATTEMPT" =~ ^[0-9]+$ ]] ||
|
|
{ [ "$EVENT_NAME" != "workflow_dispatch" ] && [ "$ATTEMPT" != "1" ]; }; then
|
|
echo "Rerun advice only covers Playwright UI Tests (first attempt, or the latest attempt when started by hand)."
|
|
exit 0
|
|
fi
|
|
RUN_EVENT=$(jq -r '.event' <<< "$RUN")
|
|
HEAD_SHA=$(jq -r '.headSha' <<< "$RUN")
|
|
PR=""
|
|
BASE=""
|
|
if [ "$RUN_EVENT" = "pull_request" ]; then
|
|
PR="$PR_NUMBER"
|
|
BASE="$PR_BASE"
|
|
# Fork PRs leave workflow_run.pull_requests empty and are not found by commits/{sha}/pulls.
|
|
if [ -z "$PR" ]; then
|
|
read -r PR BASE <<< "$(GH_TOKEN="$COMMENT_TOKEN" gh pr list --repo "$GH_REPO" --search "$HEAD_SHA" --state open \
|
|
--json number,baseRefName --jq '.[0] // empty | "\(.number) \(.baseRefName)"' 2>/dev/null)" || true
|
|
fi
|
|
else
|
|
BASE=$(jq -r '.headBranch' <<< "$RUN")
|
|
fi
|
|
|
|
newer_on_main() {
|
|
local latest status
|
|
latest=$(gh api "repos/$OSS_REPO/commits?sha=main&path=$1&per_page=1" --jq '.[0].sha // empty') || return 2
|
|
[ -n "$latest" ] || return 1
|
|
status=$(gh api "repos/$OSS_REPO/compare/$TESTED_SHA...$latest" --jq '.status') || return 2
|
|
# diverged: the tested commit is off main (a PR merge commit or a paired openobserve branch) and lacks that commit.
|
|
case "$status" in
|
|
ahead|diverged) return 0 ;;
|
|
behind|identical) return 1 ;;
|
|
*) return 2 ;;
|
|
esac
|
|
}
|
|
|
|
decide() {
|
|
local count files f rc newer="" all=true
|
|
if ! count=$(jq -r '.failed_count' "$1" 2>/dev/null) || ! [[ "$count" =~ ^[0-9]{1,6}$ ]]; then
|
|
NOTE="No rerun advice from this run (missing, unreadable or failed_count -1); rerunning the failed jobs as before."
|
|
return
|
|
fi
|
|
if [ "$count" -ge 25 ]; then
|
|
MESSAGE="$count tests failed at once, which usually means the server or runner broke rather than the tests; rerunning only the failed tests."
|
|
return
|
|
fi
|
|
# Release and feature branches lag main by design, so comparing them with main would skip every rerun.
|
|
if [ "$BASE" != "main" ]; then
|
|
NOTE="This run's base is '${BASE:-unknown}', not main, so the newer-on-main check is skipped; rerunning the failed jobs."
|
|
return
|
|
fi
|
|
if ! files=$(jq -r '.failed_files | if type == "array" and all(.[]; type == "string") then unique[] else error end' "$1" 2>/dev/null) ||
|
|
! TESTED_SHA=$(jq -r '.tested_oss_sha' "$1") || ! [[ "$TESTED_SHA" =~ ^[0-9a-f]{40}$ ]]; then
|
|
NOTE="Rerun advice was unreadable; rerunning the failed jobs as before."
|
|
return
|
|
fi
|
|
mapfile -t FILES < <(printf '%s' "$files")
|
|
if [ "${#FILES[@]}" -eq 0 ] || [ "${#FILES[@]}" -gt "$count" ]; then
|
|
NOTE="No usable list of failed test files ($count failed tests); rerunning the failed jobs as before."
|
|
return
|
|
fi
|
|
for f in "${FILES[@]}"; do
|
|
# The artifact may come from a fork PR, so only well-formed paths reach the API and the comment.
|
|
if ! [[ "$f" =~ ^tests/ui-testing/[A-Za-z0-9._/-]+$ ]] || [[ "$f" == *..* ]]; then
|
|
NOTE="Rerun advice listed an unexpected file path; rerunning the failed jobs as before."
|
|
return
|
|
fi
|
|
rc=0
|
|
newer_on_main "$f" || rc=$?
|
|
case "$rc" in
|
|
0) newer+="- \`$f\`"$'\n' ;;
|
|
1) all=false ;;
|
|
*) NOTE="Could not compare the failed test files with main (GitHub API error); rerunning the failed jobs as before."
|
|
return ;;
|
|
esac
|
|
done
|
|
if [ -z "$newer" ]; then
|
|
NOTE="No failed test file has a newer version on main than the copy this run tested; rerunning the failed jobs."
|
|
elif [ "$all" != true ]; then
|
|
MESSAGE="Rerunning the failed tests. Some failed test files have a newer version on main than the copy this run tested, so the rerun replays the old copies of these:"$'\n\n'"$newer"$'\n'"$HOW_TO_UPDATE to test them with the newer versions."
|
|
elif [ "$RUN_EVENT" != "pull_request" ]; then
|
|
MESSAGE="Rerunning the failed tests, because only pull request runs skip reruns (the PR comment explains the skip). Every failed test file has a newer version on main than the copy this run tested, so the rerun replays the old copies of these:"$'\n\n'"$newer"
|
|
else
|
|
SKIP=true
|
|
MESSAGE="Not rerunning. Every failed test file has a newer version on main than the copy this run tested:"$'\n\n'"$newer"$'\n'"A rerun would replay the old copies. $HOW_TO_UPDATE to test with the newer versions."
|
|
fi
|
|
}
|
|
|
|
upsert_comment() {
|
|
local me cid
|
|
# The PAT can edit anyone's comment, so only a marker comment it wrote itself is updated.
|
|
me=$(GH_TOKEN="$COMMENT_TOKEN" gh api user --jq .login) && [ -n "$me" ] || return 1
|
|
cid=$(GH_TOKEN="$COMMENT_TOKEN" gh api "repos/$GH_REPO/issues/$PR/comments" --paginate \
|
|
-q ".[] | select(.user.login == \"$me\" and (.body | contains(\"$MARKER\"))) | .id") || return 1
|
|
cid=${cid%%$'\n'*}
|
|
if [ -n "$cid" ]; then
|
|
GH_TOKEN="$COMMENT_TOKEN" gh api -X PATCH "repos/$GH_REPO/issues/comments/$cid" -f body="$1" > /dev/null
|
|
else
|
|
GH_TOKEN="$COMMENT_TOKEN" gh api -X POST "repos/$GH_REPO/issues/$PR/comments" -f body="$1" > /dev/null
|
|
fi
|
|
}
|
|
|
|
HOW_TO_UPDATE="Push again or rebase (for Enterprise runs, the openobserve branch with the same name)"
|
|
SKIP=false
|
|
MESSAGE=""
|
|
NOTE=""
|
|
COMMENTED=false
|
|
DIR=$(mktemp -d)
|
|
gh run download "$RUN_ID" --repo "$GH_REPO" -n "rerun-advice-attempt-$ATTEMPT" -D "$DIR" > /dev/null 2>&1 || true
|
|
decide "$DIR/rerun-advice.json"
|
|
if [ -n "$MESSAGE" ] && [[ "$PR" =~ ^[0-9]+$ ]] && [ -n "$COMMENT_TOKEN" ]; then
|
|
BODY="$MARKER"$'\n'"### Playwright rerun advice"$'\n\n'"Run: $(jq -r '.url' <<< "$RUN") (commit \`${HEAD_SHA:0:10}\`)"$'\n\n'"$MESSAGE"
|
|
if upsert_comment "$BODY"; then
|
|
COMMENTED=true
|
|
echo "Upserted the rerun advice comment on PR #$PR."
|
|
else
|
|
echo "::warning::Could not post the rerun advice comment on PR #$PR."
|
|
fi
|
|
fi
|
|
# A silent skip leaves a red check nobody explains, so skipping needs the PR comment to land.
|
|
if [ "$SKIP" = true ] && [ "$COMMENTED" != true ]; then
|
|
SKIP=false
|
|
MESSAGE="Rerunning anyway, because this advice could not be posted on the PR. ${MESSAGE#Not rerunning. }"
|
|
fi
|
|
echo "skip_rerun=$SKIP" >> "$GITHUB_OUTPUT"
|
|
{ echo "### Playwright rerun advice"; echo; echo "${MESSAGE:-$NOTE}"; } >> "$GITHUB_STEP_SUMMARY"
|
|
echo "${MESSAGE:-$NOTE}"
|
|
|
|
- name: Verify workflow status and trigger rerun
|
|
env:
|
|
GH_REPO: ${{ github.repository }}
|
|
GH_TOKEN: ${{ github.token }}
|
|
EVENT_NAME: ${{ github.event_name }}
|
|
WR_ID: ${{ github.event.workflow_run.id }}
|
|
INPUT_RUN_ID: ${{ inputs.run_id }}
|
|
SKIP_RERUN: ${{ steps.advice.outputs.skip_rerun }}
|
|
run: |
|
|
echo "::group::Determining workflow run ID"
|
|
|
|
# Determine run ID based on trigger type
|
|
if [ "$EVENT_NAME" = "workflow_dispatch" ]; then
|
|
RUN_ID="$INPUT_RUN_ID"
|
|
echo "::notice::Manual trigger mode"
|
|
echo "::notice::Run ID from input: $RUN_ID"
|
|
else
|
|
RUN_ID="$WR_ID"
|
|
echo "::notice::Automatic trigger mode (workflow_run)"
|
|
echo "::notice::Run ID from workflow_run event: $RUN_ID"
|
|
fi
|
|
|
|
echo "::endgroup::"
|
|
|
|
# Verify the run exists and get its details
|
|
echo "::group::Fetching workflow run details"
|
|
|
|
RUN_INFO=$(gh run view "$RUN_ID" --repo "$GH_REPO" --json conclusion,status,databaseId,attempt,event 2>&1)
|
|
|
|
if [ $? -ne 0 ]; then
|
|
echo "::error::Failed to fetch run information for run ID $RUN_ID"
|
|
echo "::error::Error: $RUN_INFO"
|
|
exit 1
|
|
fi
|
|
|
|
echo "Run information:"
|
|
echo "$RUN_INFO" | jq '.'
|
|
|
|
CONCLUSION=$(echo "$RUN_INFO" | jq -r '.conclusion')
|
|
STATUS=$(echo "$RUN_INFO" | jq -r '.status')
|
|
ATTEMPT=$(echo "$RUN_INFO" | jq -r '.attempt')
|
|
|
|
echo "::notice::Workflow conclusion: $CONCLUSION"
|
|
echo "::notice::Workflow status: $STATUS"
|
|
echo "::notice::Current attempt: $ATTEMPT"
|
|
|
|
echo "::endgroup::"
|
|
|
|
# Verify workflow is in correct state for rerun
|
|
echo "::group::Validating rerun eligibility"
|
|
|
|
if [ "$STATUS" != "completed" ]; then
|
|
echo "::error::Workflow is not completed (status: $STATUS). Cannot rerun a workflow that is still running."
|
|
exit 1
|
|
fi
|
|
|
|
if [ "$CONCLUSION" != "failure" ] && [ "$EVENT_NAME" != "workflow_dispatch" ]; then
|
|
echo "::warning::Workflow did not fail (conclusion: $CONCLUSION). Skipping rerun."
|
|
echo "::notice::This is expected if the workflow succeeded or was cancelled manually."
|
|
exit 0
|
|
fi
|
|
|
|
echo "::notice::✅ Workflow is eligible for rerun"
|
|
echo "::endgroup::"
|
|
|
|
if [ "$SKIP_RERUN" = "true" ]; then
|
|
echo "::notice::Not rerunning: every failed test file has a newer version on main than the copy this run tested (see the job summary)."
|
|
exit 0
|
|
fi
|
|
|
|
# Trigger the rerun
|
|
echo "::group::Triggering workflow rerun"
|
|
echo "::notice::Executing: gh run rerun $RUN_ID --failed --repo $GH_REPO"
|
|
|
|
RERUN_OUTPUT=$(gh run rerun "$RUN_ID" --failed --repo "$GH_REPO" 2>&1)
|
|
RERUN_EXIT_CODE=$?
|
|
|
|
if [ $RERUN_EXIT_CODE -eq 0 ]; then
|
|
echo "::notice::✅ Successfully triggered rerun of failed jobs"
|
|
echo "::notice::Run ID: $RUN_ID"
|
|
echo "::notice::Only failed and cancelled jobs will be rerun"
|
|
echo "$RERUN_OUTPUT"
|
|
else
|
|
echo "::error::❌ Failed to trigger rerun (exit code: $RERUN_EXIT_CODE)"
|
|
echo "::error::Error output:"
|
|
echo "$RERUN_OUTPUT"
|
|
|
|
# Provide helpful debugging information
|
|
echo "::error::Possible issues:"
|
|
echo "::error::1. Workflow may already be running a rerun"
|
|
echo "::error::2. Insufficient permissions (needs 'actions: write')"
|
|
echo "::error::3. Workflow run may be too old or deleted"
|
|
echo "::error::4. GitHub API rate limit reached"
|
|
|
|
exit 1
|
|
fi
|
|
|
|
echo "::endgroup::"
|