diff --git a/.github/workflows/handle_metadata.yml b/.github/workflows/handle_metadata.yml index ba0be77b4..fad90f2ae 100644 --- a/.github/workflows/handle_metadata.yml +++ b/.github/workflows/handle_metadata.yml @@ -76,126 +76,154 @@ jobs: run: | # split the comma-separated plugin-dir input into an array. IFS=',' read -ra PLUGIN_DIRS <<< "${{ inputs.plugin-dir }}" - pr_numbers="" + metadata_paths="" + db_flag="" + if [ "${{ inputs.db-connection }}" = "true" ]; then + db_flag="--db-connection" + fi + for dir in "${PLUGIN_DIRS[@]}"; do echo "Processing metadata in directory: $dir" 1>&2 - pr_num=$(python -m brainscore_core.plugin_management.handle_metadata --plugin-dir "$dir" --plugin-type "${{ inputs.plugin-type }}" --db-connection) - echo "PR number for $dir: $pr_num" 1>&2 - # Append to the list (if multiple directories are provided) - if [ -z "$pr_numbers" ]; then - pr_numbers="$pr_num" - else - pr_numbers="$pr_numbers,$pr_num" + # Use --skip-pr to prevent individual PR creation; collect metadata paths instead + meta_path=$(python -m brainscore_core.plugin_management.handle_metadata --plugin-dir "$dir" --plugin-type "${{ inputs.plugin-type }}" $db_flag --skip-pr) + echo "Metadata path for $dir: $meta_path" 1>&2 + if [ -n "$meta_path" ]; then + if [ -z "$metadata_paths" ]; then + metadata_paths="$meta_path" + else + metadata_paths="$metadata_paths,$meta_path" fi + fi done - echo "pr_numbers=${pr_numbers}" >> $GITHUB_OUTPUT - - - name: Auto-approve PRs - if: steps.run_metadata.outputs.pr_numbers != '' + echo "metadata_paths=${metadata_paths}" >> $GITHUB_OUTPUT + + - name: Create Combined PR + id: create_pr + if: steps.run_metadata.outputs.metadata_paths != '' env: - GITHUB_TOKEN: ${{ secrets.APPROVAL_TOKEN }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - IFS=',' read -ra PR_ARRAY <<< "${{ steps.run_metadata.outputs.pr_numbers }}" - for pr in "${PR_ARRAY[@]}"; do - echo "Auto-approving PR #$pr" 1>&2 - gh pr review $pr --approve --repo ${{ github.repository }} + # Create a single branch and PR for all metadata files + branch_name="auto/metadata-update_$(date +%s)" + git checkout -b "$branch_name" + + IFS=',' read -ra PATHS <<< "${{ steps.run_metadata.outputs.metadata_paths }}" + for path in "${PATHS[@]}"; do + echo "Adding metadata file: $path" + git add "$path" done + + git commit -m "Auto-add/update metadata.yml for ${#PATHS[@]} plugin(s)" + git push origin "$branch_name" + + pr_title="Auto-add/update metadata.yml for ${#PATHS[@]} plugin(s)" + pr_body="This PR was automatically generated to add or update metadata.yml files for the following plugins:\n\n$(printf '- %s\n' "${PATHS[@]}")" + gh pr create --title "$pr_title" --body "$pr_body" --label "automerge-metadata" + + sleep 5 + pr_number=$(gh pr view --json number --jq '.number') + echo "pr_number=${pr_number}" >> $GITHUB_OUTPUT + - name: Auto-approve PR + if: steps.create_pr.outputs.pr_number != '' + env: + GITHUB_TOKEN: ${{ secrets.APPROVAL_TOKEN }} + run: | + pr=${{ steps.create_pr.outputs.pr_number }} + echo "Auto-approving PR #$pr" + gh pr review $pr --approve --repo ${{ github.repository }} + - name: Wait for Status Checks - if: steps.run_metadata.outputs.pr_numbers != '' + if: steps.create_pr.outputs.pr_number != '' env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - IFS=',' read -ra PR_ARRAY <<< "${{ steps.run_metadata.outputs.pr_numbers }}" + pr=${{ steps.create_pr.outputs.pr_number }} TOKEN="${{ secrets.GITHUB_TOKEN }}" - MAX_WAIT=600 # 10 minutes maximum wait time per PR + MAX_WAIT=600 # 10 minutes maximum wait time SLEEP_INTERVAL=10 - - for pr in "${PR_ARRAY[@]}"; do - echo "Waiting for status checks on PR #$pr" - commit_sha=$(gh pr view $pr --json headRefOid --jq '.headRefOid') - echo "Commit SHA for PR #$pr is $commit_sha" - - # initial delay to allow statuses to start being reported - echo "Sleeping for initial delay (30s) to allow statuses to be reported..." - sleep 30 - ELAPSED=30 - - while true; do - echo "Polling statuses for PR #$pr (commit $commit_sha)" - statuses=$(curl -s -H "Authorization: token $TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${{ github.repository }}/commits/$commit_sha/statuses") - - # get required status checks for the branch - branch=$(gh pr view $pr --json headRefName --jq '.headRefName') - required_checks=$(curl -s -H "Authorization: token $TOKEN" \ - -H "Accept: application/vnd.github+json" \ - "https://api.github.com/repos/${{ github.repository }}/branches/$branch/protection" | \ - jq -r '.required_status_checks.contexts[]' 2>/dev/null || echo "") - - # process the latest status for each context - latest_statuses=$(echo "$statuses" | jq '[group_by(.context)[] | max_by(.created_at)]') - - # count by state - pending=$(echo "$latest_statuses" | jq 'map(select(.state=="pending")) | length') - failures=$(echo "$latest_statuses" | jq 'map(select(.state=="failure" or .state=="error")) | length') - successes=$(echo "$latest_statuses" | jq 'map(select(.state=="success")) | length') - total=$(echo "$latest_statuses" | jq 'length') - - # list the current statuses for visibility - echo "$latest_statuses" | jq -r '.[] | " - \(.context): \(.state)"' | sort - echo "Status summary: $pending pending, $failures failures, $successes successes (total: $total)" - - # check for required status checks - missing_required=0 - if [ ! -z "$required_checks" ]; then - echo "Required status checks for branch $branch:" - echo "$required_checks" | while read -r check; do - exists=$(echo "$latest_statuses" | jq --arg check "$check" 'map(select(.context == $check)) | length') - if [ "$exists" -eq 0 ]; then - echo " - $check: MISSING" - missing_required=1 - else - state=$(echo "$latest_statuses" | jq -r --arg check "$check" '.[] | select(.context == $check) | .state') - echo " - $check: $state" - fi - done - else - echo "No required status checks found for branch $branch" - fi - - if [ "$failures" -gt 0 ]; then - echo "❌ One or more status checks failed for PR #$pr - aborting" - exit 1 - fi - - if [ "$pending" -eq 0 ] && [ "$missing_required" -eq 0 ]; then - echo "✅ All status checks passed for PR #$pr" - break - fi - - # sleep and check again - sleep $SLEEP_INTERVAL - ELAPSED=$((ELAPSED + SLEEP_INTERVAL)) - if [ "$ELAPSED" -ge "$MAX_WAIT" ]; then - echo "⏱️ Timeout of $MAX_WAIT seconds reached for PR #$pr - aborting" - exit 1 - fi - - echo "Waiting for status checks to complete (elapsed time: ${ELAPSED}s)..." - done + + echo "Waiting for status checks on PR #$pr" + commit_sha=$(gh pr view $pr --json headRefOid --jq '.headRefOid') + echo "Commit SHA for PR #$pr is $commit_sha" + + # initial delay to allow statuses to start being reported + echo "Sleeping for initial delay (30s) to allow statuses to be reported..." + sleep 30 + ELAPSED=30 + + while true; do + echo "Polling statuses for PR #$pr (commit $commit_sha)" + statuses=$(curl -s -H "Authorization: token $TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/commits/$commit_sha/statuses") + + # get required status checks for the branch + branch=$(gh pr view $pr --json headRefName --jq '.headRefName') + required_checks=$(curl -s -H "Authorization: token $TOKEN" \ + -H "Accept: application/vnd.github+json" \ + "https://api.github.com/repos/${{ github.repository }}/branches/$branch/protection" | \ + jq -r '.required_status_checks.contexts[]' 2>/dev/null || echo "") + + # process the latest status for each context + latest_statuses=$(echo "$statuses" | jq '[group_by(.context)[] | max_by(.created_at)]') + + # count by state + pending=$(echo "$latest_statuses" | jq 'map(select(.state=="pending")) | length') + failures=$(echo "$latest_statuses" | jq 'map(select(.state=="failure" or .state=="error")) | length') + successes=$(echo "$latest_statuses" | jq 'map(select(.state=="success")) | length') + total=$(echo "$latest_statuses" | jq 'length') + + # list the current statuses for visibility + echo "$latest_statuses" | jq -r '.[] | " - \(.context): \(.state)"' | sort + echo "Status summary: $pending pending, $failures failures, $successes successes (total: $total)" + + # check for required status checks + missing_required=0 + if [ ! -z "$required_checks" ]; then + echo "Required status checks for branch $branch:" + echo "$required_checks" | while read -r check; do + exists=$(echo "$latest_statuses" | jq --arg check "$check" 'map(select(.context == $check)) | length') + if [ "$exists" -eq 0 ]; then + echo " - $check: MISSING" + missing_required=1 + else + state=$(echo "$latest_statuses" | jq -r --arg check "$check" '.[] | select(.context == $check) | .state') + echo " - $check: $state" + fi + done + else + echo "No required status checks found for branch $branch" + fi + + if [ "$failures" -gt 0 ]; then + echo "One or more status checks failed for PR #$pr - aborting" + exit 1 + fi + + if [ "$pending" -eq 0 ] && [ "$missing_required" -eq 0 ]; then + echo "All status checks passed for PR #$pr" + break + fi + + # sleep and check again + sleep $SLEEP_INTERVAL + ELAPSED=$((ELAPSED + SLEEP_INTERVAL)) + if [ "$ELAPSED" -ge "$MAX_WAIT" ]; then + echo "Timeout of $MAX_WAIT seconds reached for PR #$pr - aborting" + exit 1 + fi + + echo "Waiting for status checks to complete (elapsed time: ${ELAPSED}s)..." done - - echo "All PRs have passed their status checks!" - - - name: Merge PRs - if: steps.run_metadata.outputs.pr_numbers != '' + + echo "PR has passed all status checks!" + + - name: Merge PR + if: steps.create_pr.outputs.pr_number != '' env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | - IFS=',' read -ra PR_ARRAY <<< "${{ steps.run_metadata.outputs.pr_numbers }}" - for pr in "${PR_ARRAY[@]}"; do - echo "Merging PR #$pr" 1>&2 - gh pr merge $pr --squash --delete-branch --repo ${{ github.repository }} - done + pr=${{ steps.create_pr.outputs.pr_number }} + echo "Merging PR #$pr" + gh pr merge $pr --squash --delete-branch --repo ${{ github.repository }}