2525 - ' main'
2626 - ' release/**'
2727
28+ # Poll for open pull requests that need labels every 5 minutes
29+ schedule :
30+ - cron : " */5 * * * *"
31+
2832 # Allow dispatching the workflow via the Actions UI, specifying ranges of numbers
33+ # If no pull request numbers are provided, it behaves as a polling event
2934 workflow_dispatch :
3035 inputs :
3136 pulls :
32- description : " Pull Request Numbers (comma-separated list of ranges)."
33- required : true
37+ description : " Pull Request Numbers (comma-separated list of ranges). Leave empty to poll. "
38+ required : false
3439 cache_key :
3540 description : " The cache key suffix to use for restoring the model. Defaults to 'ACTIVE'."
3641 required : true
4550 DEFAULT_LABEL : " needs-area-label"
4651
4752jobs :
53+ poll-pull-requests :
54+ # Run on schedule trigger or workflow_dispatch without PR numbers, within the 'dotnet' org
55+ if : ${{ (github.event_name == 'schedule' || (github.event_name == 'workflow_dispatch' && inputs.pulls == '')) && github.repository_owner == 'dotnet' }}
56+ runs-on : ubuntu-latest
57+ permissions :
58+ actions : read
59+ pull-requests : read
60+ outputs :
61+ pulls : ${{ steps.get-pulls.outputs.pulls }}
62+ steps :
63+ - name : " Get open pull requests needing labels"
64+ id : get-pulls
65+ env :
66+ GITHUB_TOKEN : ${{ github.token }}
67+ run : |
68+ # Get the last successful schedule run's timestamp (minus 5 minutes for overlap)
69+ last_run=$(gh run list --repo ${{ github.repository }} --workflow "${{ github.workflow }}" --event schedule --status success --limit 1 --json updatedAt --jq '.[0].updatedAt // empty')
70+
71+ if [ -n "$last_run" ]; then
72+ # Subtract 5 minutes from the last run timestamp for overlap
73+ since=$(date -u -d "$last_run - 5 minutes" +"%Y-%m-%dT%H:%M:%SZ")
74+ echo "Filtering PRs updated since: $since (last run: $last_run)"
75+ pulls=$(gh pr list --repo ${{ github.repository }} --state open --json number,labels,updatedAt --limit 1000 --search "updated:>=$since")
76+ else
77+ # No previous run found; get all open pull requests
78+ echo "No previous schedule run found. Getting all open pull requests."
79+ pulls=$(gh pr list --repo ${{ github.repository }} --state open --json number,labels --limit 1000)
80+ fi
81+
82+ # Filter to PRs that don't have a label starting with LABEL_PREFIX
83+ needs_label=$(echo "$pulls" | jq -r --arg prefix "${{ env.LABEL_PREFIX }}" '
84+ [.[] | select(
85+ (.labels | map(.name) | any(startswith($prefix)) | not)
86+ ) | .number] | join(",")
87+ ')
88+
89+ echo "Pull requests needing labels: $needs_label"
90+ echo "pulls=$needs_label" >> $GITHUB_OUTPUT
91+
4892 predict-pull-label :
93+ # The 'if' uses always() so this job runs even when poll-pull-requests is skipped
4994 # Do not automatically run the workflow on forks outside the 'dotnet' org
50- if : ${{ github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet' }}
95+ if : ${{ always() && (github.event_name == 'workflow_dispatch' || github.repository_owner == 'dotnet') }}
96+ needs : [poll-pull-requests]
5197 runs-on : ubuntu-latest
5298 permissions :
5399 pull-requests : write
54100 steps :
101+ - name : " Determine pull requests to process"
102+ id : determine-pulls
103+ run : |
104+ if [ "${{ github.event_name }}" == "workflow_dispatch" ] && [ -n "${{ inputs.pulls }}" ]; then
105+ pulls="${{ inputs.pulls }}"
106+ elif [ "${{ github.event_name }}" == "workflow_dispatch" ] || [ "${{ github.event_name }}" == "schedule" ]; then
107+ pulls="${{ needs.poll-pull-requests.outputs.pulls }}"
108+ else
109+ pulls="${{ github.event.number }}"
110+ fi
111+ echo "pulls=$pulls" >> $GITHUB_OUTPUT
112+ echo "Processing pull requests: $pulls"
113+
55114 - name : " Restore pulls model from cache"
56115 id : restore-model
116+ if : ${{ steps.determine-pulls.outputs.pulls != '' }}
57117 uses : dotnet/issue-labeler/restore@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0
58118 with :
59119 type : pulls
@@ -62,10 +122,10 @@ jobs:
62122
63123 - name : " Predict pull labels"
64124 id : prediction
65- if : ${{ steps.restore-model.outputs.cache-hit == 'true' }}
125+ if : ${{ steps.determine-pulls.outputs.pulls != '' && steps. restore-model.outputs.cache-hit == 'true' }}
66126 uses : dotnet/issue-labeler/predict@46125e85e6a568dc712f358c39f35317366f5eed # v2.0.0
67127 with :
68- pulls : ${{ inputs. pulls || github.event.number }}
128+ pulls : ${{ steps.determine- pulls.outputs.pulls }}
69129 label_prefix : ${{ env.LABEL_PREFIX }}
70130 threshold : ${{ env.THRESHOLD }}
71131 default_label : ${{ env.DEFAULT_LABEL }}
0 commit comments