PR automation #33
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# This workflow finds all PRs in all repos and adds them to the | |
# project if they have the right label | |
name: Scheduled PR automation | |
on: | |
# schedule: | |
# # * is a special character in YAML so you have to quote this string | |
# - cron: '30 5,17 * * *' | |
workflow_dispatch: | |
jobs: | |
get_prs: | |
name: Get all PRs with the bot label | |
runs-on: ubuntu-latest | |
outputs: | |
urls: ${{ steps.get_pr.outputs.pr_urls }} | |
steps: | |
- name: Get current repositories | |
id: get_pr | |
env: | |
GH_TOKEN: ${{ secrets.LAB_PAT }} | |
MAX_REPO: 50 | |
run: | | |
pr_urls=$(gh search prs label:_bot --state open --json 'url' | jq -c '[.[].url]') | |
echo "pr_urls=${pr_urls}" >> $GITHUB_OUTPUT | |
process_prs: | |
name: Process PR | |
runs-on: ubuntu-latest | |
env: | |
GH_TOKEN: ${{ secrets.NB_PROJECT_PAT }} | |
needs: get_prs | |
strategy: | |
fail-fast: false | |
matrix: | |
url: ${{fromJSON(needs.get_prs.outputs.urls)}} | |
steps: | |
- name: Check if PR is in project | |
id: in_project | |
continue-on-error: true | |
run: | | |
gh pr view ${{ matrix.url }} --json 'projectItems' | jq -r '.projectItems[0].title' | grep Neurobagel | |
- name: Add PR to project | |
if: steps.in_project.outcome == 'failure' | |
run: | | |
gh pr edit ${{ matrix.url }} --add-project Neurobagel | |
- name: Find project node id | |
id: project_node | |
run: | | |
# Get the node ID of the PR | |
node_id=$(gh pr view ${{ matrix.url }} --json 'id' | jq -r '.id') | |
parent_id=$( | |
newCursor="" | |
while true; do | |
response=$(gh api graphql -f query='{ | |
organization(login: "neurobagel") { | |
projectV2(number: 1) { | |
items(first: 100, orderBy: {field: POSITION, direction: DESC}, after: "'"${newCursor}"'") { | |
edges { | |
cursor | |
node { | |
content { | |
... on PullRequest { | |
childID: id | |
} | |
} | |
parentID: id | |
} | |
} | |
} | |
} | |
} | |
}') | |
# Because we may not be able to find the parent ID in the first 100 items | |
# we have to keep advancing the cursor to move through the list | |
# Note: we use 100 items to balance speed and API limits, might have to be changed | |
while read -r pID cID cursor; do | |
if [ "$cID" == "${node_id}" ]; | |
then | |
echo $pID; | |
exit 0; | |
fi | |
newCursor="$cursor" | |
# Note: we need to use the here string | |
# to avoid running the while loop in a subshell that would not let us access newCursor | |
# after the while loop has finished | |
# see: https://tldp.org/LDP/abs/html/subshells.html | |
done <<< $(echo "$response" | jq -r '.data.organization.projectV2.items.edges[] | "\(.node.parentID) \(.node.content.childID) \(.cursor)"') | |
if [ ! -n "$newCursor" ]; then | |
# We have passed through the entire list of items | |
# and didn't find the project card for our PR. | |
# Something is wrong and we will now crash the workflow. | |
exit 1; | |
fi | |
done | |
) | |
echo "parent_id=${parent_id}" >> $GITHUB_OUTPUT | |
- name: Get IDs for Status field and Community option | |
id: get_id | |
env: | |
FIELD: "Status" | |
OPTION: "Community" | |
run: | | |
response=$(gh api graphql -f query='{ | |
organization(login: "neurobagel") { | |
projectV2(number: 1) { | |
field(name: "'"${FIELD}"'") { | |
... on ProjectV2SingleSelectField { | |
fieldID: id | |
options(names: "'"${OPTION}"'") { | |
optionID: id | |
} | |
} | |
} | |
} | |
} | |
}' | jq '.data.organization.projectV2.field | "\(.fieldID) \(.options[0].optionID)"') | |
read fieldID optionID <<< "${response//\"}" | |
echo "fieldID=${fieldID}" >> $GITHUB_OUTPUT | |
echo "optionID=${optionID}" >> $GITHUB_OUTPUT | |
- name: Set "Status" of PR to "Community" | |
run: | | |
gh api graphql -f query='mutation { | |
updateProjectV2ItemFieldValue( | |
input: {projectId: "PVT_kwDOBaeejM4AAQiP", itemId: "${{ steps.project_node.outputs.parent_id }}", fieldId: "${{ steps.get_id.outputs.fieldID }}", value: {singleSelectOptionId: "${{ steps.get_id.outputs.optionID }}"}} | |
) { | |
clientMutationId | |
} | |
}' |