Skip to content

Commit 6f41ed3

Browse files
committed
Add PR Dependency check workflow
1 parent c188fe5 commit 6f41ed3

2 files changed

Lines changed: 143 additions & 0 deletions

File tree

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
name: Check for Dependencies in PR
2+
3+
on:
4+
pull_request:
5+
types: [opened, reopened, edited, labeled, unlabeled, synchronize]
6+
7+
jobs:
8+
check-dependency:
9+
runs-on: ubuntu-latest
10+
steps:
11+
- name: Check PR dependencies and merge status
12+
# Check if dependent PRs are merged before allowing this PR to merge
13+
run: |
14+
set -e
15+
16+
# Function to check if a PR is merged
17+
check_pr_merged() {
18+
local pr_ref=$1
19+
local repo=""
20+
local pr_number=""
21+
22+
# Parse PR reference - supports multiple formats:
23+
# 1. #123 (same repo)
24+
# 2. owner/repo#123 (different repo)
25+
# 3. https://github.com/owner/repo/pull/123 (GitHub URL)
26+
if [[ "$pr_ref" =~ ^https://github\.com/([^/]+/[^/]+)/pull/([0-9]+)$ ]]; then
27+
# GitHub URL format: https://github.com/owner/repo/pull/123
28+
repo="${BASH_REMATCH[1]}"
29+
pr_number="${BASH_REMATCH[2]}"
30+
elif [[ "$pr_ref" =~ ^([^#]+)#([0-9]+)$ ]]; then
31+
# Cross-repository reference: owner/repo#123
32+
repo="${BASH_REMATCH[1]}"
33+
pr_number="${BASH_REMATCH[2]}"
34+
elif [[ "$pr_ref" =~ ^#([0-9]+)$ ]]; then
35+
# Same repository reference: #123
36+
repo="$GITHUB_REPOSITORY"
37+
pr_number="${BASH_REMATCH[1]}"
38+
else
39+
echo "::error::Invalid PR reference format: $pr_ref"
40+
return 1
41+
fi
42+
43+
echo "Checking PR #$pr_number in repository $repo..."
44+
45+
local api_response=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
46+
"https://api.github.com/repos/$repo/pulls/$pr_number")
47+
48+
if echo "$api_response" | jq -e '.message == "Not Found"' >/dev/null 2>&1; then
49+
echo "::error::Referenced PR $repo#$pr_number does not exist or is not accessible"
50+
return 1
51+
fi
52+
53+
local merged=$(echo "$api_response" | jq -r '.merged')
54+
local state=$(echo "$api_response" | jq -r '.state')
55+
56+
if [ "$merged" = "true" ]; then
57+
echo "✓ PR $repo#$pr_number is merged"
58+
return 0
59+
elif [ "$state" = "open" ]; then
60+
echo "::error::PR $repo#$pr_number is still open and not merged"
61+
return 1
62+
elif [ "$state" = "closed" ]; then
63+
echo "::error::PR $repo#$pr_number is closed but not merged"
64+
return 1
65+
else
66+
echo "::error::PR $repo#$pr_number has unknown state: $state"
67+
return 1
68+
fi
69+
}
70+
71+
# Function to extract PR dependencies from text
72+
extract_dependencies() {
73+
local text=$1
74+
# Match patterns like:
75+
# - "depends on #123"
76+
# - "depends on owner/repo#123"
77+
# - "depends on https://github.com/owner/repo/pull/123"
78+
# - "requires #456"
79+
# - "requires owner/repo#456"
80+
# - "requires https://github.com/owner/repo/pull/456"
81+
echo "$text" | grep -iEo "(depends on|requires):?\s+(https://github\.com/[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+/pull/[0-9]+|[a-zA-Z0-9._-]+/[a-zA-Z0-9._-]+#[0-9]+|#[0-9]+)" | \
82+
sed -E 's/(depends on|requires):?\s+//i' | sort -u
83+
}
84+
85+
# Extract PR body and check for dependencies
86+
PR_BODY=$(cat $GITHUB_EVENT_PATH | jq -r '.pull_request.body // ""')
87+
88+
echo "Checking PR description for dependencies..."
89+
DEPENDENCIES=$(extract_dependencies "$PR_BODY")
90+
91+
TOTAL_FAILED_CHECKS=0
92+
93+
if [ -n "$DEPENDENCIES" ]; then
94+
echo "Found PR dependencies in description:"
95+
echo "$DEPENDENCIES"
96+
97+
while IFS= read -r dependency; do
98+
if [ -n "$dependency" ]; then
99+
if ! check_pr_merged "$dependency"; then
100+
TOTAL_FAILED_CHECKS=$((TOTAL_FAILED_CHECKS + 1))
101+
fi
102+
fi
103+
done <<< "$DEPENDENCIES"
104+
else
105+
echo "No PR dependencies found in description."
106+
fi
107+
108+
# Also check commit messages for dependencies
109+
echo "Checking commit messages for dependencies..."
110+
COMMITS_URL=$(cat $GITHUB_EVENT_PATH | jq -r '.pull_request.commits_url')
111+
COMMIT_MESSAGES=$(curl -s -H "Authorization: token $GITHUB_TOKEN" "$COMMITS_URL" | jq -r '.[].commit.message' | tr '\n' ' ')
112+
113+
COMMIT_DEPENDENCIES=$(extract_dependencies "$COMMIT_MESSAGES")
114+
115+
if [ -n "$COMMIT_DEPENDENCIES" ]; then
116+
echo "Found PR dependencies in commit messages:"
117+
echo "$COMMIT_DEPENDENCIES"
118+
119+
while IFS= read -r dependency; do
120+
if [ -n "$dependency" ]; then
121+
if ! check_pr_merged "$dependency"; then
122+
TOTAL_FAILED_CHECKS=$((TOTAL_FAILED_CHECKS + 1))
123+
fi
124+
fi
125+
done <<< "$COMMIT_DEPENDENCIES"
126+
else
127+
echo "No PR dependencies found in commit messages."
128+
fi
129+
130+
# Final check - block if any dependencies are unmerged
131+
if [ $TOTAL_FAILED_CHECKS -gt 0 ]; then
132+
echo "::error::This PR has $TOTAL_FAILED_CHECKS unmerged dependencies. Please wait for dependent PRs to be merged before merging this PR."
133+
exit 1
134+
else
135+
echo "✅ All PR dependencies are satisfied. This PR can proceed to merge."
136+
fi
137+
138+
env:
139+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

.github/workflows/pull_request.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@ on:
88
types: [opened, reopened, synchronize]
99

1010
jobs:
11+
pr_dependency_check:
12+
name: PR Dependency Check
13+
uses: ./.github/workflows/check_pr_dependency.yml
14+
1115
tests_with_docker_embedded_swift:
1216
name: Test Embedded Swift SDKs
1317
uses: ./.github/workflows/swift_package_test.yml

0 commit comments

Comments
 (0)