You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Bring dotnet/.github workflow templates into alignment with dotnet/issue-labeler v2.1.0
Scope
This issue tracks the full set of changes required in dotnet/.github/workflow-templates to align the publicly published Issue Labeler workflow templates with the v2.1.0 release of dotnet/issue-labeler (release SHA 98f1d9b85686147ffdc155547cdd3469546c4e26, predictor image digest sha256:79b5359ae5c85b90d9a98dcf3864163ae0a248f6d60687b7e81c8a189b8219a6).
The companion update to this wiki landed in dotnet/issue-labeler.wiki (commits b850f8d "wiki: align with v2.1.0" and cb4862e "wiki: update v2.1.0 SHAs and clarify release-body / tag / branch HEAD relationship") and provides an end-to-end reference walkthrough that adopters can compare against the published templates.
No template PR is opened by this issue — this is a planning/tracking issue describing the change set so maintainers (or a follow-up effort) can execute the refresh as a coordinated unit.
v2.1.0 fixes a latent string-coercion bug in ALLOW_FAILURE handling that silently broke manual bulk-dispatch runs on v2.0. The same bug is currently present in the published dotnet/.github predict templates.
v2.1.0 introduces per-type prediction thresholds, per-type max_labels, a dry_run input, a 10-row training-data minimum with friendly skip behavior, a friendlier fork guard, and a discussions: write/issues: write permission pairing for the (new) discussion predict workflow.
Templates affected
Five existing templates plus one new template (and their .properties.json siblings):
The v2.1.0 release SHA (98f1d9b85686147ffdc155547cdd3469546c4e26) is what consumers must pin to. This is what the release body advertises and what the v2.1.0-release tag points to. The v2.1.0 branch HEAD may advance past this SHA with post-release maintenance commits (currently at dedab068d5b2fcc6f85fee4ea9e9be79c3f12449) — do not pin to the branch HEAD. See the Release Process wiki page for the full relationship between these SHAs.
This is broken. In GitHub Actions expression syntax, every non-empty string is truthy — including the strings "true" and "false" themselves. !env.ALLOW_FAILURE therefore evaluates to false unconditionally, regardless of which branch produced the value. Likewise fail-on-cache-miss: ${{ env.ALLOW_FAILURE }} is always truthy.
The symptom: manual workflow_dispatch bulk-labeling runs (where the intent is to fail loudly on errors) instead silently continue, and the cache-miss guard is on when it should be off. This is the opposite of the design intent.
v2.1.0 fixes this with two coupled changes that must be applied together — either change alone is still wrong:
fromJSON("true") → true; fromJSON("false") → false. With the wrapper, the boolean expressions evaluate as intended; without it, they collapse to a string-truthiness check.
Warning
Existing v2.0 consumers (notably dotnet/runtime) mirror this broken pattern in their checked-in workflow YAML. Refreshing the published templates will fix the bug for new adopters; existing adopters need a separate heads-up so they can apply the same two-change fix to their copies. See the wiki Onboarding callout for the explanatory text adopters can reference.
Apply this fix in all predict templates: labeler-predict-issues.yml, labeler-predict-pulls.yml, and the new labeler-predict-discussions.yml.
(3) Capability changes to surface in the templates
Per-type prediction thresholds (read from repo vars)
Both labeler-train.yml and the predict templates should read per-type thresholds with a sensible fallback chain:
…and every contains(fromJSON('["Both", …]'), …) predicate switches to '["All", …]', with new download-discussions, check-discussions-data, train-discussions, test-discussions jobs mirroring the existing issues/pulls jobs.
10-row training-data minimum
Each check-<type>-data job restores the cached TSV, counts lines, and emits has_training_data=true|false. Train and test jobs depend on the corresponding check and gate on needs.check-<type>-data.outputs.has_training_data == 'true'. When the data is too small, the run notes the skip in the job summary instead of failing. (See the v2.1.0 reference workflow for the canonical implementation.)
Apply in all predict workflows and in labeler-cache-retention.yml. The new guard works correctly for repositories outside the dotnet org while still skipping automatic runs on forks.
labeler-predict-pulls.yml permissions
The predict-pulls workflow needs bothpull-requests: write and issues: write. GitHub's labels API treats issue and pull request labels uniformly through the same endpoint, and that endpoint requires issues: write even when the target is a pull request.
Add a promote-discussions job mirroring promote-issues/promote-pulls and passing type: "discussions". The promote action accepts discussions as of v2.1.0.
Also move the actions: write permission from a top-level permissions: block to per-job permissions blocks (the v2.1.0 reference workflow uses per-job permissions everywhere, with a top-level permissions: {}).
INPUT_ISSUES_MODEL: labeler-cache/discussions-model.zip on the predict step — discussions reuse the issues pipeline but the model lives at the discussions path; this env override tells the predictor where to find it.
.properties.json description should make clear the template is for repos with GitHub Discussions enabled that want automated area labeling on discussion creation.
Today the dotnet/.github workflow templates and this wiki each contain a header comment that frames itself as imported from the other:
dotnet/.github/workflow-templates/labeler-*.yml header → "imported from dotnet/issue-labeler/wiki/Onboarding"
dotnet/issue-labeler.wiki/Onboarding.md snippet headers (now removed in the wiki update) → previously said "imported and updated from dotnet/issue-labeler/wiki/Onboarding" (a circular reference)
Recommended resolution:
dotnet/.github/workflow-templates/labeler-*.yml becomes the canonical published template.
The wiki Onboarding page is the walkthrough/example that mirrors the canonical templates.
Drop the "imported from" header comments from the published templates entirely (or replace them with a one-line pointer such as # Reference: https://github.com/dotnet/issue-labeler — pinned to v2.1.0).
The wiki has been updated unilaterally on its side; the dotnet/.github side change should land alongside this template refresh.
(6) Capability matrix README
Add a short workflow-templates/README.md (or similar) explaining which v2.1.0 capabilities the templates intentionally do/do not surface, so consumers and the wiki know what is deliberate versus accidental. Suggested coverage:
v2.1.0 capability
Surfaced in templates?
Notes
Per-type prediction thresholds via repo vars
?
Decide whether to expose via env (template) or document as repo-level config
Per-type max_labels via repo vars
?
Same
dry_run input on predict workflows
?
Useful for adopters validating a new model on demand
discussions predict template
new
Opt-in; only useful for repos with Discussions enabled
10-row training-data minimum
yes
The check-data jobs are part of the canonical train template
!github.event.repository.fork guard
yes
Works for any org, not just dotnet
Filling this table is part of the work — the rows above just enumerate the decisions that need to be made.
(7) Open question — should the templates expose dry_run and max_labels as with: inputs?
The v2.1.0 predict workflows accept a dry_run boolean dispatch input (default false) and read MAX_LABELS from env. The dotnet/.github templates can either:
Option A: Stay narrow — omit the dry_run dispatch input and rely on repo vars for MAX_LABELS. Simpler templates; adopters who want dry_run add it themselves.
Option B: Mirror the v2.1.0 reference exactly — expose dry_run on dispatch, surface MAX_LABELS via repo vars in the env block. Richer out-of-the-box experience; matches what the wiki documents.
Recommendation: Option B, to keep the templates and the wiki walkthrough in lockstep. The capability matrix README should document the choice either way.
Resolve "imported from" header comments per Governance section
Add a capability-matrix README
Decide and document the dry_run / max_labels exposure question
This issue was opened in dotnet/issue-labeler rather than dotnet/.github because the source-of-truth content lives here. Maintainers of dotnet/.github should reference this issue when planning the corresponding template-refresh PR in that repository.
Bring
dotnet/.githubworkflow templates into alignment withdotnet/issue-labelerv2.1.0Scope
This issue tracks the full set of changes required in
dotnet/.github/workflow-templatesto align the publicly published Issue Labeler workflow templates with thev2.1.0release ofdotnet/issue-labeler(release SHA98f1d9b85686147ffdc155547cdd3469546c4e26, predictor image digestsha256:79b5359ae5c85b90d9a98dcf3864163ae0a248f6d60687b7e81c8a189b8219a6).The companion update to this wiki landed in
dotnet/issue-labeler.wiki(commitsb850f8d"wiki: align with v2.1.0" andcb4862e"wiki: update v2.1.0 SHAs and clarify release-body / tag / branch HEAD relationship") and provides an end-to-end reference walkthrough that adopters can compare against the published templates.Why now
ALLOW_FAILUREhandling that silently broke manual bulk-dispatch runs on v2.0. The same bug is currently present in the publisheddotnet/.githubpredict templates.max_labels, adry_runinput, a 10-row training-data minimum with friendly skip behavior, a friendlier fork guard, and adiscussions: write/issues: writepermission pairing for the (new) discussion predict workflow.Templates affected
Five existing templates plus one new template (and their
.properties.jsonsiblings):workflow-templates/labeler-train.ymlworkflow-templates/labeler-predict-issues.ymlworkflow-templates/labeler-predict-pulls.ymlworkflow-templates/labeler-promote.ymlworkflow-templates/labeler-cache-retention.ymlworkflow-templates/labeler-predict-discussions.yml+.properties.json(1) Mechanical SHA repin
Replace every
uses:reference from the current v2.0.0 SHA to the v2.1.0 SHA:Important
The v2.1.0 release SHA (
98f1d9b85686147ffdc155547cdd3469546c4e26) is what consumers must pin to. This is what the release body advertises and what thev2.1.0-releasetag points to. Thev2.1.0branch HEAD may advance past this SHA with post-release maintenance commits (currently atdedab068d5b2fcc6f85fee4ea9e9be79c3f12449) — do not pin to the branch HEAD. See the Release Process wiki page for the full relationship between these SHAs.(2) CRITICAL bug fix —
ALLOW_FAILUREpolarity &fromJSON()wrapThe v2.0 predict templates carry this pattern:
This is broken. In GitHub Actions expression syntax, every non-empty string is truthy — including the strings
"true"and"false"themselves.!env.ALLOW_FAILUREtherefore evaluates tofalseunconditionally, regardless of which branch produced the value. Likewisefail-on-cache-miss: ${{ env.ALLOW_FAILURE }}is always truthy.The symptom: manual
workflow_dispatchbulk-labeling runs (where the intent is to fail loudly on errors) instead silently continue, and the cache-miss guard is on when it should be off. This is the opposite of the design intent.v2.1.0 fixes this with two coupled changes that must be applied together — either change alone is still wrong:
fromJSON("true")→true;fromJSON("false")→false. With the wrapper, the boolean expressions evaluate as intended; without it, they collapse to a string-truthiness check.Warning
Existing v2.0 consumers (notably
dotnet/runtime) mirror this broken pattern in their checked-in workflow YAML. Refreshing the published templates will fix the bug for new adopters; existing adopters need a separate heads-up so they can apply the same two-change fix to their copies. See the wiki Onboarding callout for the explanatory text adopters can reference.Apply this fix in all predict templates:
labeler-predict-issues.yml,labeler-predict-pulls.yml, and the newlabeler-predict-discussions.yml.(3) Capability changes to surface in the templates
Per-type prediction thresholds (read from repo vars)
Both
labeler-train.ymland the predict templates should read per-type thresholds with a sensible fallback chain:Variables (all optional, all repository-level):
ISSUE_LABELER_PREDICTION_THRESHOLD0.15ISSUE_LABELER_PREDICTION_THRESHOLD_ISSUESISSUE_LABELER_PREDICTION_THRESHOLD→0.15ISSUE_LABELER_PREDICTION_THRESHOLD_PULLSISSUE_LABELER_PREDICTION_THRESHOLD→0.15ISSUE_LABELER_PREDICTION_THRESHOLD_DISCUSSIONSISSUE_LABELER_PREDICTION_THRESHOLD→0.15Per-type
max_labels(read from repo vars)Same fallback pattern, plus per-type vars
ISSUE_LABELER_MAX_LABELS_ISSUES,_PULLS,_DISCUSSIONS. Range is1–10.Training type dispatch options
labeler-train.ymlshould change:…and every
contains(fromJSON('["Both", …]'), …)predicate switches to'["All", …]', with newdownload-discussions,check-discussions-data,train-discussions,test-discussionsjobs mirroring the existing issues/pulls jobs.10-row training-data minimum
Each
check-<type>-datajob restores the cached TSV, counts lines, and emitshas_training_data=true|false. Train and test jobs depend on the corresponding check and gate onneeds.check-<type>-data.outputs.has_training_data == 'true'. When the data is too small, the run notes the skip in the job summary instead of failing. (See the v2.1.0 reference workflow for the canonical implementation.)Fork guard
Apply in all predict workflows and in
labeler-cache-retention.yml. The new guard works correctly for repositories outside thedotnetorg while still skipping automatic runs on forks.labeler-predict-pulls.ymlpermissionsThe predict-pulls workflow needs both
pull-requests: writeandissues: write. GitHub's labels API treats issue and pull request labels uniformly through the same endpoint, and that endpoint requiresissues: writeeven when the target is a pull request.permissions: + issues: write pull-requests: writePromote workflow — add discussions
pulls: description: "Pulls: Promote Model" type: boolean required: true + discussions: + description: "Discussions: Promote Model" + type: boolean + required: trueAdd a
promote-discussionsjob mirroringpromote-issues/promote-pullsand passingtype: "discussions". Thepromoteaction acceptsdiscussionsas of v2.1.0.Also move the
actions: writepermission from a top-levelpermissions:block to per-job permissions blocks (the v2.1.0 reference workflow uses per-job permissions everywhere, with a top-levelpermissions: {}).Cache retention — add
discussionsto matrixConsumers without Discussions can remove
"discussions"from their copy.(4) NEW template —
labeler-predict-discussions.ymlAdd a new template + properties file modeled on the v2.1.0 reference workflow.
Workflow shape (key elements):
Key requirements:
discussions: writeandissues: write.INPUT_ISSUES_MODEL: labeler-cache/discussions-model.zipon the predict step — discussions reuse the issues pipeline but the model lives at the discussions path; this env override tells the predictor where to find it..properties.jsondescription should make clear the template is for repos with GitHub Discussions enabled that want automated area labeling on discussion creation.(5) Governance — resolve circular source-of-truth wording
Today the
dotnet/.githubworkflow templates and this wiki each contain a header comment that frames itself as imported from the other:dotnet/.github/workflow-templates/labeler-*.ymlheader → "imported fromdotnet/issue-labeler/wiki/Onboarding"dotnet/issue-labeler.wiki/Onboarding.mdsnippet headers (now removed in the wiki update) → previously said "imported and updated fromdotnet/issue-labeler/wiki/Onboarding" (a circular reference)Recommended resolution:
dotnet/.github/workflow-templates/labeler-*.ymlbecomes the canonical published template.# Reference: https://github.com/dotnet/issue-labeler — pinned to v2.1.0).The wiki has been updated unilaterally on its side; the
dotnet/.githubside change should land alongside this template refresh.(6) Capability matrix README
Add a short
workflow-templates/README.md(or similar) explaining which v2.1.0 capabilities the templates intentionally do/do not surface, so consumers and the wiki know what is deliberate versus accidental. Suggested coverage:max_labelsvia repo varsdry_runinput on predict workflowsdiscussionspredict template!github.event.repository.forkguarddotnetFilling this table is part of the work — the rows above just enumerate the decisions that need to be made.
(7) Open question — should the templates expose
dry_runandmax_labelsaswith:inputs?The v2.1.0 predict workflows accept a
dry_runboolean dispatch input (defaultfalse) and readMAX_LABELSfrom env. Thedotnet/.githubtemplates can either:dry_rundispatch input and rely on repo vars forMAX_LABELS. Simpler templates; adopters who wantdry_runadd it themselves.dry_runon dispatch, surfaceMAX_LABELSvia repo vars in the env block. Richer out-of-the-box experience; matches what the wiki documents.Recommendation: Option B, to keep the templates and the wiki walkthrough in lockstep. The capability matrix README should document the choice either way.
References
Checklist for the refresh PR
uses:to98f1d9b85686147ffdc155547cdd3469546c4e26 # v2.1.0fromJSON()wrap in both predict templates (and the new discussions template)labeler-train.ymltype options toAll/Issues/Discussions/Pull Requestswith per-type threshold envdownload-discussions,check-*-data,train-discussions,test-discussionsjobs tolabeler-train.ymldiscussionsinput +promote-discussionsjob tolabeler-promote.yml!github.event.repository.forkin all predict workflows + cache-retentionissues: writepermission tolabeler-predict-pulls.yml"discussions"tolabeler-cache-retention.ymlmatrixlabeler-predict-discussions.yml+.properties.jsondry_run/max_labelsexposure questionThis issue was opened in
dotnet/issue-labelerrather thandotnet/.githubbecause the source-of-truth content lives here. Maintainers ofdotnet/.githubshould reference this issue when planning the corresponding template-refresh PR in that repository.