Skip to content

Update .github/workflows/track-review-project.yaml #1

Update .github/workflows/track-review-project.yaml

Update .github/workflows/track-review-project.yaml #1

# ------------------------------------------------------------------------------
# (c) Crown copyright Met Office. All rights reserved.
# The file LICENCE, distributed with this code, contains details of the terms
# under which the code may be used.
# ------------------------------------------------------------------------------
# This workflow runs whenever a pull request in the repository is marked as
# "Ready for review" (i.e., a non-Draft PR).
name: Track Review Project
on:
workflow_call:
inputs:
runner:
description: 'The runner to use for the job'
required: false
type: string
default: 'ubuntu-24.04'
project_org:
description: 'The organization that owns the project'
required: false
type: string
default: 'MetOffice'
project_number:
description: 'The project number'
required: false
type: number
default: 376 # Simulation Systems Review Tracker
permissions:
actions: read
contents: read
pull-requests: write
jobs:
track_project:
runs-on: ${{ inputs.runner }}
timeout-minutes: 5
env:
REPO: ${{ github.repository }}
steps:
# Required as running from the workflow_run trigger
- name: Checkout repo
uses: actions/checkout@v6
- name: Download PR data artifact
uses: actions/github-script@v8
with:
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
let allArtifacts = await github.rest.actions.listWorkflowRunArtifacts({
owner: context.repo.owner,
repo: context.repo.repo,
run_id: context.payload.workflow_run.id,
});
let matchArtifact = allArtifacts.data.artifacts.filter((artifact) => {
return artifact.name == "context.json"
})[0];
let download = await github.rest.actions.downloadArtifact({
owner: context.repo.owner,
repo: context.repo.repo,
artifact_id: matchArtifact.id,
archive_format: 'zip',
});
let fs = require('fs');
fs.writeFileSync(`${process.env.GITHUB_WORKSPACE}/context.zip`, Buffer.from(download.data));

Check failure on line 70 in .github/workflows/track-review-project.yaml

View workflow run for this annotation

GitHub Actions / .github/workflows/track-review-project.yaml

Invalid workflow file

You have an error in your yaml syntax on line 70
- name: Extract PR Data
run: |
unzip context.zip
pr_num=$(jq -r '.pr_num' context.json)
pr_id=$(jq -r '.pr_id' context.json)
echo "PR_NUM=$pr_num" >> $GITHUB_ENV
unzip -q context.zip
jq -r '"PR_NUM=\(.pr_num)\nPR_ID=\(.pr_id)"' context.json >> $GITHUB_ENV
- name: Assign Author if no assignees
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
pr_data=$(gh pr view -R "$REPO" "$PR_NUM" --json assignees,author)
if [[ $(echo "$pr_data" | jq '.assignees | length') -eq 0 ]]; then
author=$(echo "$pr_data" | jq -r '.author.login')
gh pr edit -R "$REPO" "$PR_NUM" --add-assignee "$author"
fi
- name: Extract reviewers and determine state
env:
GH_TOKEN: ${{ github.token }}
run: |
pr_data=$(gh pr view -R "$REPO" "$PR_NUM" --json body,reviews,reviewRequests)
# Extract reviewers from PR body
pr_body=$(echo "$pr_data" | jq -r '.body')
scitech_reviewer=$(echo "$pr_body" | grep -oP "Sci/Tech Reviewer:\s?@\K([\w\-]{1,39})\b" || true)
code_reviewer=$(echo "$pr_body" | grep -oP "Code Reviewer:\s?@\K([\w\-]{1,39})\b" || true)
echo "Expected SciTech Reviewer: ${scitech_reviewer:-None}"
echo "Expected Code Reviewer: ${code_reviewer:-None}"
echo "SCITECH_REVIEWER=$scitech_reviewer" >> $GITHUB_ENV
echo "CODE_REVIEWER=$code_reviewer" >> $GITHUB_ENV
# Determine review state
reviews=$(echo "$pr_data" | jq -c '{reviews, reviewRequests}')
sr_requested=$(echo "$reviews" | jq --arg sr "$scitech_reviewer" '[.reviewRequests[] | select(.login == $sr)] | length')
cr_requested=$(echo "$reviews" | jq --arg cr "$code_reviewer" '[.reviewRequests[] | select(.login == $cr)] | length')
# Determine required state
sr_approved=$(echo "$reviews" | jq --arg sr "$scitech_reviewer" '[.reviews[] | select(.author.login == $sr and .state == "APPROVED")] | length')
sr_changes=$(echo "$reviews" | jq --arg sr "$scitech_reviewer" '[.reviews[] | select(.author.login == $sr and (.state == "CHANGES_REQUESTED" or .state == "COMMENTED"))] | length')
[[ ! -z "$scitech_reviewer" ]] && [[ "$sr_requested" -eq 0 ]] && [[ "$sr_approved" -eq 0 ]] && [[ "$sr_changes" -eq 0 ]] && echo "SR_REQUEST_REQUIRED=true" >> $GITHUB_ENV
if [[ -z "$scitech_reviewer" ]] && [[ "$cr_requested" -gt 0 ]]; then
echo "No SR set and CR requested so assuming this is trivial"
else
if [[ "$sr_approved" -eq 0 ]]; then
if [[ -z "$scitech_reviewer" ]] && [[ "$sr_changes" -eq 0 ]]; then
required_state="In Progress"
elif [[ "$sr_changes" -gt 0 ]] && [[ "$sr_requested" -eq 0 ]]; then
required_state="Changes Requested"
else
required_state="SciTech Review"
fi
echo "REQUIRED_STATE=$required_state" >> $GITHUB_ENV
exit 0
fi
fi
cr_approved=$(echo "$reviews" | jq --arg cr "$code_reviewer" '[.reviews[] | select(.author.login == $cr and .state == "APPROVED")] | length')
cr_changes=$(echo "$reviews" | jq --arg cr "$code_reviewer" '[.reviews[] | select(.author.login == $cr and (.state == "CHANGES_REQUESTED" or .state == "COMMENTED"))] | length')
if [[ "$cr_approved" -gt 0 ]]; then
required_state="Approved"
elif [[ "cr_changes" -eq 0 ]] && [[ "$cr_requested" -eq 0 ]] && [[ "$sr_approved" -eq 0 ]]; then
required_state="In Progress"
elif [[ "$cr_changes" -gt 0 ]] && [[ "$cr_requested" -eq 0 ]]; then
required_state="Changes Requested"
else
required_state="Code Review"
[[ "$cr_requested" -eq 0 ]] && [[ "$cr_approved" -eq 0 ]] && [[ "$cr_changes" -eq 0 ]] && echo "CR_REQUEST_REQUIRED=true" >> $GITHUB_ENV
fi
echo "REQUIRED_STATE=$required_state" >> $GITHUB_ENV
- name: Request SciTech review, if needed
if: env.SR_REQUEST_REQUIRED == 'true' && env.REQUIRED_STATE == 'SciTech Review' && env.SCITECH_REVIEWER != ''
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: gh pr edit -R "$REPO" "$PR_NUM" --add-reviewer "$SCITECH_REVIEWER"
- name: Request code review, if needed
if: env.CR_REQUEST_REQUIRED == 'true' && env.REQUIRED_STATE == 'Code Review' && env.CODE_REVIEWER != ''
continue-on-error: true
env:
GH_TOKEN: ${{ github.token }}
run: |
gh pr edit -R "$REPO" "$PR_NUM" --add-reviewer "$CODE_REVIEWER"
- name: Update project tracking
env:
GH_TOKEN: ${{ secrets.PROJECT_ACTION_PAT }}
run: |
# Get project data
project_data=$(gh api graphql -f query='
query($org: String!, $number: Int!) {
organization(login: $org){
projectV2(number: $number) {
id
fields(first:20) {
nodes {
... on ProjectV2Field { id name }
... on ProjectV2SingleSelectField { id name options { id name } }
}
}
}
}
}' -f org=${{ inputs.project_org }} -F number=${{ inputs.project_number }})
project_id=$(echo "$project_data" | jq -r '.data.organization.projectV2.id')
status_field_id=$(echo "$project_data" | jq -r '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .id')
status_option_id=$(echo "$project_data" | jq -r --arg status "$REQUIRED_STATE" '.data.organization.projectV2.fields.nodes[] | select(.name== "Status") | .options[] | select(.name==$status) | .id')
scitech_field_id=$(echo "$project_data" | jq -r '.data.organization.projectV2.fields.nodes[] | select(.name== "SciTech Review") | .id')
code_field_id=$(echo "$project_data" | jq -r '.data.organization.projectV2.fields.nodes[] | select(.name== "Code Review") | .id')
# Add PR to project and update fields
item_id=$(gh api graphql -f query='
mutation($project:ID!, $pr:ID!) {
addProjectV2ItemById(input: {projectId: $project, contentId: $pr}) {
item { id }
}
}' -f project="$project_id" -f pr="$PR_ID" --jq '.data.addProjectV2ItemById.item.id')
# Update all fields in single mutation
gh api graphql -f query='
mutation($project: ID!, $item: ID!, $status_field: ID!, $status_value: String!, $cr_field: ID!, $cr_value: String!, $sr_field: ID!, $sr_value: String!) {
set_status: updateProjectV2ItemFieldValue(input: {projectId: $project, itemId: $item, fieldId: $status_field, value: {singleSelectOptionId: $status_value}}) { projectV2Item { id } }
set_code_review: updateProjectV2ItemFieldValue(input: {projectId: $project, itemId: $item, fieldId: $cr_field, value: {text: $cr_value}}) { projectV2Item { id } }
set_scitech_review: updateProjectV2ItemFieldValue(input: {projectId: $project, itemId: $item, fieldId: $sr_field, value: {text: $sr_value}}) { projectV2Item { id } }
}' -f project="$project_id" -f item="$item_id" -f status_field="$status_field_id" -f status_value="$status_option_id" -f cr_field="$code_field_id" -f cr_value="$CODE_REVIEWER" -f sr_field="$scitech_field_id" -f sr_value="$SCITECH_REVIEWER" --silent