summaryrefslogtreecommitdiffstats
path: root/.github/workflows/gate_postcommits_manual_control.yml
blob: fb06ba82fd77a272efb88ec1ff70466811556205 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
name: Manual Gate Control
on:
  workflow_dispatch:
    inputs:
      action:
        description: 'Action to perform'
        required: true
        default: 'open'
        type: choice
        options:
          - open
          - close
      count_of_runners_to_change_label:
        description: 'Optional: Number of runners to change (leave empty for all)'
        required: false
        type: string

jobs:
  manage_gate:
    runs-on: ubuntu-latest
    name: Manual Gate Control
    steps:
    - name: Set Gate State
      shell: bash
      run: |
        echo "Performing manual gate ${{ github.event.inputs.action }} operation"
        
        # Set limit count if provided
        LIMIT_COUNT="${{ github.event.inputs.count_of_runners_to_change_label }}"
        if [[ -n "$LIMIT_COUNT" && "$LIMIT_COUNT" =~ ^[0-9]+$ ]]; then
          echo "Will change labels for up to $LIMIT_COUNT runners"
          LIMIT_OPTION=true
        else
          echo "Will change labels for all applicable runners"
          LIMIT_OPTION=false
        fi
        
        if [[ "${{ github.event.inputs.action }}" == "close" ]]; then
          echo "Closing gate for postcommits - removing postcommit labels"
          query='.runners[] | select(.labels[].name=="ghrun") | select( any([.labels[].name][]; .=="postcommit")) | .id'
          OPERATION="Closing"
          LABEL_ACTION="Removing"
        else
          echo "Opening gate for postcommits - adding postcommit labels"
          query='.runners[] | select(.labels[].name=="ghrun") | select( all([.labels[].name][]; .!="postcommit")) | .id'
          OPERATION="Opening"
          LABEL_ACTION="Adding"
        fi
        
        # Function to fetch a page of runners
        fetch_runners_page() {
          local page=$1
          echo "Fetching runners page $page..."
          local result=$(curl -Ls -H "Accept: application/vnd.github+json" -H "Authorization: Bearer ${{secrets.GH_PERSONAL_ACCESS_TOKEN}}" \
            -H "X-GitHub-Api-Version: 2022-11-28" -w "%{http_code}\n" \
            "https://api.github.com/repos/${{github.repository}}/actions/runners?per_page=100&page=$page")
          
          local http_code=$(echo "$result" | tail -n 1)
          if [ "$http_code" != "200" ]; then
            echo "HTTP error fetching page $page: $http_code"
            echo "$result"
            return 1
          fi
          
          # Remove status code from the end
          echo "$result" | sed '$d'
        }
        
        # Get all runners with pagination
        echo "Collecting all runners (paginated)..."
        page=1
        all_runner_ids=()
        more_pages=true
        
        while $more_pages; do
          runners_data=$(fetch_runners_page $page)
          if [ $? -ne 0 ]; then
            echo "Failed to fetch runners page $page, exiting"
            exit 1
          fi
          
          # Extract runner IDs for this page
          readarray -t page_ids < <(echo "$runners_data" | jq -r "$query" | grep -v "^$")
          
          # Check if we have runners on this page
          count_on_page=${#page_ids[@]}
          echo "Found $count_on_page eligible runners on page $page"
          
          # Append to our array
          all_runner_ids+=("${page_ids[@]}")
          
          # Check if we have more pages
          runners_count=$(echo "$runners_data" | jq '.runners | length')
          if [ $runners_count -lt 100 ]; then
            more_pages=false
          else
            page=$((page + 1))
          fi
        done
        
        # Count total eligible runners
        total_runners=${#all_runner_ids[@]}
        echo "Total eligible runners found across all pages: $total_runners"
        
        # Limit if needed
        if [[ "$LIMIT_OPTION" == "true" && $total_runners -gt $LIMIT_COUNT ]]; then
          all_runner_ids=("${all_runner_ids[@]:0:$LIMIT_COUNT}")
          echo "Limited to first $LIMIT_COUNT runners"
        fi
        
        # Files to store results and details
        success_file=$(mktemp)
        failed_file=$(mktemp)
        details_file=$(mktemp)
        
        # Process runners
        changed_count=0
        for runner_id in "${all_runner_ids[@]}"; do
          changed_count=$((changed_count + 1))
          echo "Processing runner $changed_count/${#all_runner_ids[@]}: ID $runner_id"
          
          if [[ "${{ github.event.inputs.action }}" == "close" ]]; then
            echo "Removing postcommit label from runner $runner_id"
            response=$(curl -s -w "\n%{http_code}" -X DELETE -H "Accept: application/vnd.github+json" \
              -H "Authorization: Bearer ${{secrets.GH_PERSONAL_ACCESS_TOKEN}}" \
              -H "X-GitHub-Api-Version: 2022-11-28" \
              "https://api.github.com/repos/${{github.repository}}/actions/runners/$runner_id/labels/postcommit")
          else
            echo "Adding postcommit label to runner $runner_id"
            response=$(curl -s -w "\n%{http_code}" -X POST -H "Accept: application/vnd.github+json" \
              -H "Authorization: Bearer ${{secrets.GH_PERSONAL_ACCESS_TOKEN}}" \
              -H "X-GitHub-Api-Version: 2022-11-28" \
              "https://api.github.com/repos/${{github.repository}}/actions/runners/$runner_id/labels" \
              -d '{"labels":["postcommit"]}')
          fi
          
          # Parse response
          http_code=$(echo "$response" | tail -n1)
          body=$(echo "$response" | sed '$d')
          
          # Get runner name for better reporting
          runner_name=$(curl -s -H "Accept: application/vnd.github+json" \
            -H "Authorization: Bearer ${{secrets.GH_PERSONAL_ACCESS_TOKEN}}" \
            -H "X-GitHub-Api-Version: 2022-11-28" \
            "https://api.github.com/repos/${{github.repository}}/actions/runners/$runner_id" | \
            jq -r '.name // "Unknown"')
          
          # Check success (HTTP 2xx)
          if [[ $http_code -ge 200 && $http_code -lt 300 ]]; then
            echo "1" >> "$success_file"
            status_icon="✅"
            status_text="Success"
            echo "$status_icon Success: Label ${{ github.event.inputs.action == 'close' && 'removed' || 'added' }} for runner $runner_name (ID: $runner_id)"
          else
            echo "1" >> "$failed_file"
            status_icon="❌"
            status_text="Failed"
            echo "$status_icon Failed: HTTP $http_code for runner $runner_name (ID: $runner_id)"
            echo "Error response: $body"
          fi
          
          # Add to details for summary
          echo "| $runner_name | $runner_id | $status_text | $http_code |" >> "$details_file"
        done
        
        # Calculate success/failure counts
        success_count=$(wc -l < "$success_file")
        failed_count=$(wc -l < "$failed_file")
        
        # Create summary for GitHub Actions
        echo "## Gate Control Operation Summary" >> $GITHUB_STEP_SUMMARY
        echo "" >> $GITHUB_STEP_SUMMARY
        echo "**Action:** $OPERATION gate ($LABEL_ACTION 'postcommit' label)" >> $GITHUB_STEP_SUMMARY
        echo "**Repository:** \`${{github.repository}}\`" >> $GITHUB_STEP_SUMMARY
        echo "**Timestamp:** $(date -u '+%Y-%m-%d %H:%M:%S UTC')" >> $GITHUB_STEP_SUMMARY
        echo "" >> $GITHUB_STEP_SUMMARY
        
        echo "### Results" >> $GITHUB_STEP_SUMMARY
        echo "" >> $GITHUB_STEP_SUMMARY
        echo "| Metric | Count |" >> $GITHUB_STEP_SUMMARY
        echo "|--------|-------|" >> $GITHUB_STEP_SUMMARY
        echo "| Total eligible runners | $total_runners |" >> $GITHUB_STEP_SUMMARY
        if [[ "$LIMIT_OPTION" == "true" ]]; then
          echo "| Limit applied | $LIMIT_COUNT |" >> $GITHUB_STEP_SUMMARY
        fi
        echo "| Runners processed | $changed_count |" >> $GITHUB_STEP_SUMMARY
        echo "| ✅ Successful operations | $success_count |" >> $GITHUB_STEP_SUMMARY
        echo "| ❌ Failed operations | $failed_count |" >> $GITHUB_STEP_SUMMARY
        echo "" >> $GITHUB_STEP_SUMMARY
        
        if [[ $changed_count -gt 0 ]]; then
          echo "### Operation Details" >> $GITHUB_STEP_SUMMARY
          echo "" >> $GITHUB_STEP_SUMMARY
          echo "| Runner Name | ID | Status | HTTP Code |" >> $GITHUB_STEP_SUMMARY
          echo "|-------------|----|---------|----|" >> $GITHUB_STEP_SUMMARY
          cat "$details_file" >> $GITHUB_STEP_SUMMARY
        else
          echo "### No runners were processed" >> $GITHUB_STEP_SUMMARY
        fi
        
        # Console summary
        echo ""
        echo "=== OPERATION SUMMARY ==="
        echo "Action: ${{ github.event.inputs.action }} gate"
        echo "Total eligible runners: $total_runners"
        if [[ "$LIMIT_OPTION" == "true" ]]; then
          echo "Limited to: $LIMIT_COUNT"
        fi
        echo "Runners processed: $changed_count"
        echo "Successful operations: $success_count"
        echo "Failed operations: $failed_count"
        echo "========================="
        
        # Cleanup temp files
        rm -f "$success_file" "$failed_file" "$details_file"
        
        # Set exit code based on success
        if [[ $failed_count -gt 0 ]]; then
          echo "Warning: Some operations failed"
          echo "::warning::$failed_count operations failed. See summary for details."
          exit 1
        fi
        
        echo "Gate ${{ github.event.inputs.action }} operation completed successfully"