Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 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
122 changes: 122 additions & 0 deletions .github/workflows/pipeline-analysis-next-steps-trigger.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
# Pipeline Analysis - Next Steps (trigger / dispatcher)
#
# Plain GitHub Actions workflow that watches for a pull request's Azure DevOps CI to finish
# in a failure state, then dispatches the agentic workflow `pipeline-analysis-next-steps.md`
# (compiled to `pipeline-analysis-next-steps.lock.yml`) to analyze the failure and post a
# "Next Steps to Merge" comment.
#
# Why a separate trigger workflow (mirrors azure-sdk-for-net's mgmt-review-trigger.yml):
# * `check_suite` is not a pull_request event, so the agentic workflow cannot resolve the
# target PR on its own. This job extracts the PR number and passes it as an explicit
# workflow_dispatch input (and `aw_context`) so the agent comments on the right PR.
# * Keeps the privileged Copilot run (copilot-requests) isolated in the agentic workflow;
# this dispatcher only needs `actions: write` to start it.
#
# azure-sdk-tools CI note: unlike azure-sdk-for-net (one `net - pullrequest` check), this repo
# has many path-triggered Azure DevOps pipelines. They all report under a SINGLE
# `azure-pipelines` GitHub App check suite per commit, so we trigger on `check_suite` and gate
# on that app + a failing conclusion. Gating on the app also prevents this workflow (a
# github-actions check suite) from re-triggering itself.
name: Pipeline Analysis - Next Steps Trigger

on:
check_suite:
types: [completed]
workflow_dispatch:
inputs:
pr_number:
description: "Open pull request number to analyze"
required: true
type: string

permissions:
actions: write # dispatch the agentic (lock) workflow
contents: read
pull-requests: read

jobs:
dispatch-next-steps:
# Only react to the Azure DevOps check suite finishing in a failure state; ignore every
# other check suite (github-actions, policy service, and this workflow's own runs). Manual
# dispatch always runs.
if: >
github.event_name != 'check_suite' ||
(github.event.check_suite.app.slug == 'azure-pipelines' &&
github.event.check_suite.conclusion == 'failure')
Comment thread
ReilleyMilne marked this conversation as resolved.
Outdated
runs-on: ubuntu-latest
steps:
- name: Dispatch pipeline next-steps analysis
env:
GH_TOKEN: ${{ github.token }}
REPOSITORY: ${{ github.repository }}
DEFAULT_BRANCH: ${{ github.event.repository.default_branch }}
PR_NUMBER: ${{ github.event.check_suite.pull_requests[0].number }}
CHECK_SUITE_CONCLUSION: ${{ github.event.check_suite.conclusion }}
CHECK_SUITE_HEAD_SHA: ${{ github.event.check_suite.head_sha }}
MANUAL_PR_NUMBER: ${{ inputs.pr_number }}
run: |
set -euo pipefail

# Fork PRs do not populate check_suite.pull_requests; fall back to matching an open
# PR by head SHA (same-repo branches only).
find_open_pr_for_head_sha() {
local head_sha="$1"
[ -z "$head_sha" ] && return 0
gh api --paginate "repos/$REPOSITORY/pulls?state=open&per_page=100" \
--jq ".[] | select(.head.sha == \"$head_sha\") | [.updated_at, .number] | @tsv" |
sort -r |
sed -n '1s/^[^\t]*\t//p'
}

dispatch_next_steps() {
local pr_number="$1"
local conclusion="$2"
local head_sha="$3"

if [ -z "$pr_number" ]; then
echo "No pull request associated with this check suite; nothing to do."
return 0
fi

if [ "$(gh pr view "$pr_number" --repo "$REPOSITORY" --json isDraft --jq '.isDraft')" = "true" ]; then
echo "Skipping draft PR #$pr_number."
return 0
fi

# Do not analyze a superseded commit: if the completed suite's SHA no longer matches
# the PR head, the author has already pushed newer code.
local current_head_sha
current_head_sha="$(gh pr view "$pr_number" --repo "$REPOSITORY" --json headRefOid --jq '.headRefOid')"
if [ -n "$head_sha" ] && [ "$head_sha" != "$current_head_sha" ]; then
echo "Skipping PR #$pr_number; check suite SHA $head_sha no longer matches head $current_head_sha."
return 0
fi

local aw_context
aw_context="$(printf '{"item_type":"pull_request","item_number":%s}' "$pr_number")"

gh workflow run pipeline-analysis-next-steps.lock.yml \
--repo "$REPOSITORY" \
--ref "$DEFAULT_BRANCH" \
-f aw_context="$aw_context" \
-f pr_number="$pr_number" \
-f check_suite_conclusion="$conclusion" \
-f check_suite_head_sha="$head_sha"
echo "Dispatched pipeline next-steps analysis for PR #$pr_number."
}

if [ "$GITHUB_EVENT_NAME" = "check_suite" ]; then
if [ -z "$PR_NUMBER" ]; then
PR_NUMBER="$(find_open_pr_for_head_sha "$CHECK_SUITE_HEAD_SHA")"
fi
dispatch_next_steps "$PR_NUMBER" "$CHECK_SUITE_CONCLUSION" "$CHECK_SUITE_HEAD_SHA"
exit 0
fi

# Manual dispatch: resolve the current head SHA and run against it.
head_sha="$(gh api "repos/$REPOSITORY/pulls/$MANUAL_PR_NUMBER" --jq 'select(.state == "open") | .head.sha' 2>/dev/null || true)"
if [ -z "$head_sha" ]; then
echo "Skipping PR #$MANUAL_PR_NUMBER; PR was not found or is not open."
exit 0
fi
dispatch_next_steps "$MANUAL_PR_NUMBER" "manual" "$head_sha"
Loading
Loading