mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-04-29 22:24:26 +02:00
ci: add a workflow to detect and check dependencies for blocked pull requests (#3497)
This commit is contained in:
commit
3042e051c7
235
.github/workflows/blocked-prs.yml
vendored
Normal file
235
.github/workflows/blocked-prs.yml
vendored
Normal file
@ -0,0 +1,235 @@
|
||||
name: Blocked/Stacked Pull Requests Automation
|
||||
|
||||
on:
|
||||
pull_request_target:
|
||||
types:
|
||||
- opened
|
||||
- reopened
|
||||
- edited
|
||||
- synchronize
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
pr_id:
|
||||
description: Local Pull Request number to work on
|
||||
required: true
|
||||
type: number
|
||||
|
||||
jobs:
|
||||
blocked_status:
|
||||
name: Check Blocked Status
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Generate token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Setup From Dispatch Event
|
||||
if: github.event_name == 'workflow_dispatch'
|
||||
id: dispatch_event_setup
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
PR_NUMBER: ${{ inputs.pr_id }}
|
||||
run: |
|
||||
# setup env for the rest of the workflow
|
||||
OWNER=$(dirname "${{ github.repository }}")
|
||||
REPO=$(basename "${{ github.repository }}")
|
||||
PR_JSON=$(
|
||||
gh api \
|
||||
-H "Accept: application/vnd.github.raw+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/$OWNER/$REPO/pulls/$PR_NUMBER"
|
||||
)
|
||||
echo "PR_JSON=$PR_JSON" >> "$GITHUB_ENV"
|
||||
|
||||
- name: Setup Environment
|
||||
id: env_setup
|
||||
run: |
|
||||
# setup env for the rest of the workflow
|
||||
PR_JSON=${PR_JSON:-'${{ toJSON(github.event.pull_request) }}'}
|
||||
{
|
||||
echo "REPO=$(jq -r '.base.repo.name' <<< "$PR_JSON")"
|
||||
echo "OWNER=$(jq -r '.base.repo.owner.login' <<< "$PR_JSON")"
|
||||
echo "PR_NUMBER=$(jq -r '.number' <<< "$PR_JSON")"
|
||||
echo "JOB_DATA=$(jq -c '
|
||||
{
|
||||
"repo": .base.repo.name,
|
||||
"owner": .base.repo.owner.login,
|
||||
"repoUrl": .base.repo.html_url,
|
||||
"prNumber": .number,
|
||||
"prHeadSha": .head.sha,
|
||||
"prHeadLabel": .head.label,
|
||||
"prBody": .body,
|
||||
"prLabels": (reduce .labels[].name as $l ([]; . + [$l]))
|
||||
}
|
||||
' <<< "$PR_JSON")"
|
||||
} >> "$GITHUB_ENV"
|
||||
|
||||
|
||||
- name: Find Blocked/Stacked PRs in body
|
||||
id: pr_ids
|
||||
run: |
|
||||
prs=$(
|
||||
jq -c '
|
||||
.prBody as $body
|
||||
| (
|
||||
$body |
|
||||
reduce (
|
||||
. | scan("blocked (?:by|on):? #([0-9]+)")
|
||||
| map({
|
||||
"type": "Blocked on",
|
||||
"number": ( . | tonumber )
|
||||
})
|
||||
) as $i ([]; . + [$i[]])
|
||||
) as $bprs
|
||||
| (
|
||||
$body |
|
||||
reduce (
|
||||
. | scan("stacked on:? #([0-9]+)")
|
||||
| map({
|
||||
"type": "Stacked on",
|
||||
"number": ( . | tonumber )
|
||||
})
|
||||
) as $i ([]; . + [$i[]])
|
||||
) as $sprs
|
||||
| ($bprs + $sprs) as $prs
|
||||
| {
|
||||
"blocking": $prs,
|
||||
"numBlocking": ( $prs | length),
|
||||
}
|
||||
' <<< "$JOB_DATA"
|
||||
)
|
||||
echo "prs=$prs" >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Collect Blocked PR Data
|
||||
id: blocking_data
|
||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
BLOCKING_PRS: ${{ steps.pr_ids.outputs.prs }}
|
||||
run: |
|
||||
blocked_pr_data=$(
|
||||
while read -r pr_data ; do
|
||||
gh api \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/$OWNER/$REPO/pulls/$(jq -r '.number' <<< "$pr_data")" \
|
||||
| jq -c --arg type "$(jq -r '.type' <<< "$pr_data")" \
|
||||
'
|
||||
. | {
|
||||
"type": $type,
|
||||
"number": .number,
|
||||
"merged": .merged,
|
||||
"labels": (reduce .labels[].name as $l ([]; . + [$l])),
|
||||
"basePrUrl": .html_url,
|
||||
"baseRepoName": .head.repo.name,
|
||||
"baseRepoOwner": .head.repo.owner.login,
|
||||
"baseRepoUrl": .head.repo.html_url,
|
||||
"baseSha": .head.sha,
|
||||
"baseRefName": .head.ref,
|
||||
}
|
||||
'
|
||||
done < <(jq -c '.blocking[]' <<< "$BLOCKING_PRS") | jq -c -s
|
||||
)
|
||||
{
|
||||
echo "data=$blocked_pr_data";
|
||||
echo "all_merged=$(jq -r 'all(.[].merged; .)' <<< "$blocked_pr_data")";
|
||||
echo "current_blocking=$(jq -c 'map( select( .merged | not ) | .number )' <<< "$blocked_pr_data" )";
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Add 'blocked' Label is Missing
|
||||
id: label_blocked
|
||||
if: (fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0) && !contains(fromJSON(env.JOB_DATA).prLabels, 'blocked') && !fromJSON(steps.blocking_data.outputs.all_merged)
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
run: |
|
||||
gh -R ${{ github.repository }} issue edit --add-label 'blocked' "$PR_NUMBER"
|
||||
|
||||
- name: Remove 'blocked' Label if All Dependencies Are Merged
|
||||
id: unlabel_blocked
|
||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0 && fromJSON(steps.blocking_data.outputs.all_merged)
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
run: |
|
||||
gh -R ${{ github.repository }} issue edit --remove-label 'blocked' "$PR_NUMBER"
|
||||
|
||||
- name: Apply 'blocking' Label to Unmerged Dependencies
|
||||
id: label_blocking
|
||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
||||
continue-on-error: true
|
||||
env:
|
||||
BLOCKING_ISSUES: ${{ steps.blocking_data.outputs.current_blocking }}
|
||||
run: |
|
||||
while read -r pr ; do
|
||||
gh -R ${{ github.repository }} issue edit --add-label 'blocking' "$pr" || true
|
||||
done < <(jq -c '.[]' <<< "$BLOCKING_ISSUES")
|
||||
|
||||
- name: Apply Blocking PR Status Check
|
||||
id: blocked_check
|
||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
|
||||
run: |
|
||||
pr_head_sha=$(jq -r '.prHeadSha' <<< "$JOB_DATA")
|
||||
# create commit Status, overwrites previous identical context
|
||||
while read -r pr_data ; do
|
||||
DESC=$(
|
||||
jq -r ' "Blocking PR #" + (.number | tostring) + " is " + (if .merged then "" else "not yet " end) + "merged"' <<< "$pr_data"
|
||||
)
|
||||
gh api \
|
||||
--method POST \
|
||||
-H "Accept: application/vnd.github+json" \
|
||||
-H "X-GitHub-Api-Version: 2022-11-28" \
|
||||
"/repos/${OWNER}/${REPO}/statuses/${pr_head_sha}" \
|
||||
-f "state=$(jq -r 'if .merged then "success" else "failure" end' <<< "$pr_data")" \
|
||||
-f "target_url=$(jq -r '.basePrUrl' <<< "$pr_data" )" \
|
||||
-f "description=$DESC" \
|
||||
-f "context=ci/blocking-pr-check:$(jq '.number' <<< "$pr_data")"
|
||||
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
|
||||
|
||||
- name: Context Comment
|
||||
id: generate-comment
|
||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
||||
continue-on-error: true
|
||||
env:
|
||||
BLOCKING_DATA: ${{ steps.blocking_data.outputs.data }}
|
||||
run: |
|
||||
COMMENT_PATH="$(pwd)/temp_comment_file.txt"
|
||||
echo '<h3> PR Dependencies :pushpin:</h3>' > "$COMMENT_PATH"
|
||||
pr_head_label=$(jq -r '.prHeadLabel' <<< "$JOB_DATA")
|
||||
while read -r pr_data ; do
|
||||
base_pr=$(jq -r '.number' <<< "$pr_data")
|
||||
base_ref_name=$(jq -r '.baseRefName' <<< "$pr_data")
|
||||
base_repo_owner=$(jq -r '.baseRepoOwner' <<< "$pr_data")
|
||||
base_repo_name=$(jq -r '.baseRepoName' <<< "$pr_data")
|
||||
compare_url="https://github.com/$base_repo_owner/$base_repo_name/compare/$base_ref_name...$pr_head_label"
|
||||
status=$(jq -r 'if .merged then ":heavy_check_mark: Merged" else ":x: Not Merged" end' <<< "$pr_data")
|
||||
type=$(jq -r '.type' <<< "$pr_data")
|
||||
echo " - $type #$base_pr $status [(compare)]($compare_url)" >> "$COMMENT_PATH"
|
||||
done < <(jq -c '.[]' <<< "$BLOCKING_DATA")
|
||||
|
||||
{
|
||||
echo 'body<<EOF';
|
||||
cat "${COMMENT_PATH}";
|
||||
echo 'EOF';
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: 💬 PR Comment
|
||||
if: fromJSON(steps.pr_ids.outputs.prs).numBlocking > 0
|
||||
continue-on-error: true
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
COMMENT_BODY: ${{ steps.generate-comment.outputs.body }}
|
||||
run: |
|
||||
gh -R ${{ github.repository }} issue comment "$PR_NUMBER" \
|
||||
--body "$COMMENT_BODY" \
|
||||
--create-if-none \
|
||||
--edit-last
|
||||
|
56
.github/workflows/merge-blocking-pr.yml
vendored
Normal file
56
.github/workflows/merge-blocking-pr.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
||||
name: Merged Blocking Pull Request Automation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types:
|
||||
- closed
|
||||
|
||||
jobs:
|
||||
update-blocked-status:
|
||||
name: Update Blocked Status
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
# a pr that was a `blocking:<id>` label was merged.
|
||||
# find the open pr's it was blocked by and trigger a refresh of their state
|
||||
if: github.event.pull_request.merged == true && contains( join( github.event.pull_request.labels.*.name, ',' ), 'blocking' )
|
||||
|
||||
steps:
|
||||
- name: Generate token
|
||||
id: generate-token
|
||||
uses: actions/create-github-app-token@v1
|
||||
with:
|
||||
app-id: ${{ vars.PULL_REQUEST_APP_ID }}
|
||||
private-key: ${{ secrets.PULL_REQUEST_APP_PRIVATE_KEY }}
|
||||
|
||||
- name: Gather Dependent PRs
|
||||
id: gather_deps
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
PR_NUMBER: ${{ github.event.pull_request.number }}
|
||||
run: |
|
||||
blocked_prs=$(
|
||||
gh -R ${{ github.repository }} pr list --label 'blocked' --json 'number,body' \
|
||||
| jq -c --argjson pr "${{ github.event.pull_request.number }}" '
|
||||
reduce ( .[] | select(
|
||||
.body |
|
||||
scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") |
|
||||
map(tonumber) |
|
||||
any(.[]; . == $pr)
|
||||
)) as $i ([]; . + [$i])
|
||||
'
|
||||
)
|
||||
{
|
||||
echo "deps=$blocked_prs"
|
||||
echo "numdeps=$(jq -r '. | length' <<< "$blocked_prs")"
|
||||
} >> "$GITHUB_OUTPUT"
|
||||
|
||||
- name: Trigger Blocked PR Workflows for Dependants
|
||||
if: fromJSON(steps.gather_deps.outputs.numdeps) > 0
|
||||
env:
|
||||
GH_TOKEN: ${{ steps.generate-token.outputs.token }}
|
||||
DEPS: ${{ steps.gather_deps.outputs.deps }}
|
||||
run: |
|
||||
while read -r pr ; do
|
||||
gh -R ${{ github.repository }} workflow run 'blocked-prs.yml' -r "${{ github.ref_name }}" -f pr_id="$pr"
|
||||
done < <(jq -c '.[].number' <<< "$DEPS")
|
||||
|
Loading…
x
Reference in New Issue
Block a user