openhands / .github /workflows /issue-readiness-check.yml
SaylorTwift's picture
SaylorTwift HF Staff
Add files using upload-large-folder tool
3201ca6 verified
Raw History Blame Contribute Delete
7.44 kB
---
name: Issue Readiness Check
# Manages the `ready-for-dev` label based on type-specific readiness criteria.
#
# The type is inferred from the issue body rather than its labels: a body with
# a `##`/`### Steps to Reproduce` or `##`/`### Actual Behavior` section is
# checked as a bug report, and a body with a `##`/`### Desired Behavior`
# section is checked as an enhancement. The criteria themselves are unchanged.
# When exactly one type is inferred, the workflow also synchronizes the `bug`
# and `enhancement` labels so API-created issues do not require manual labeling.
#
# When criteria are met the label is added (idempotently); when they are not the
# label is removed. A feedback comment is posted (or updated) in three cases:
# 1. The issue is first opened or reopened — always comment so the author
# knows whether their issue is ready or what is missing.
# 2. The label is being added (issue became ready) — comment celebrating it.
# 3. The label is being removed (issue was ready but is no longer) — comment
# explaining what changed.
# Edits that do not change the label state do not produce a new comment. All
# comments are upserted by a hidden marker so there is at most one per issue.
on:
issues:
types: [opened, edited, reopened, labeled, unlabeled]
permissions:
issues: write
contents: read
concurrency:
group: issue-readiness-${{ github.event.issue.number }}
cancel-in-progress: false
jobs:
check:
if: github.event.issue.state == 'open' && github.event.issue.pull_request == null
runs-on: ubuntu-24.04
timeout-minutes: 5
steps:
- name: Checkout trusted workflow scripts
uses: actions/checkout@v7
- name: Evaluate issue readiness
id: readiness
env:
GITHUB_EVENT_PATH: ${{ github.event_path }}
run: |
set -euo pipefail
python .github/scripts/check_issue_readiness.py --json > /tmp/result.json || true
echo "ready=$(jq -r '.ready' /tmp/result.json)" >> "$GITHUB_OUTPUT"
echo "issue_type=$(jq -r '.issue_type // empty' /tmp/result.json)" >> "$GITHUB_OUTPUT"
# Write reasons to a file so the comment step can read them
# without shell-escaping multiline text.
jq -r '.reasons[]?' /tmp/result.json > /tmp/reasons.txt || true
echo "reasons_file=/tmp/reasons.txt" >> "$GITHUB_OUTPUT"
- name: Synchronize inferred issue type label
if: steps.readiness.outputs.issue_type != ''
env:
GH_TOKEN: ${{ github.token }}
ISSUE_TYPE: ${{ steps.readiness.outputs.issue_type }}
run: |
set -euo pipefail
if ! issue_labels_json=$(gh issue view \
"${{ github.event.issue.number }}" \
--repo "${{ github.repository }}" \
--json labels --jq '[.labels[].name]' 2>/tmp/gh-err.txt); then
echo "::warning::Failed to read current issue labels:" \
>> "$GITHUB_STEP_SUMMARY"
cat /tmp/gh-err.txt >> "$GITHUB_STEP_SUMMARY"
exit 0
fi
if [ "$ISSUE_TYPE" = "bug" ]; then
other_type="enhancement"
else
other_type="bug"
fi
label_args=()
if ! jq -e --arg label "$ISSUE_TYPE" \
'index($label) != null' <<< "$issue_labels_json" >/dev/null; then
label_args+=(--add-label "$ISSUE_TYPE")
fi
if jq -e --arg label "$other_type" \
'index($label) != null' <<< "$issue_labels_json" >/dev/null; then
label_args+=(--remove-label "$other_type")
fi
if [ "${#label_args[@]}" -eq 0 ]; then
exit 0
fi
if ! gh issue edit "${{ github.event.issue.number }}" \
--repo "${{ github.repository }}" \
"${label_args[@]}" 2>/tmp/gh-err.txt; then
echo "::warning::Failed to synchronize inferred issue type label:" \
>> "$GITHUB_STEP_SUMMARY"
cat /tmp/gh-err.txt >> "$GITHUB_STEP_SUMMARY"
fi
- name: Add ready-for-dev label
if: steps.readiness.outputs.ready == 'true'
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
# Capture stderr — tolerate "label already present" (exit 0
# from gh) but surface unexpected errors to the step summary.
if ! gh issue edit "${{ github.event.issue.number }}" \
--repo "${{ github.repository }}" \
--add-label "ready-for-dev" 2>/tmp/gh-err.txt; then
echo "::warning::Failed to add ready-for-dev label:" >> "$GITHUB_STEP_SUMMARY"
cat /tmp/gh-err.txt >> "$GITHUB_STEP_SUMMARY"
fi
- name: Remove ready-for-dev label
if: steps.readiness.outputs.ready != 'true' && contains(github.event.issue.labels.*.name, 'ready-for-dev')
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
# Capture stderr — tolerate "label already removed" but
# surface unexpected errors.
if ! gh issue edit "${{ github.event.issue.number }}" \
--repo "${{ github.repository }}" \
--remove-label "ready-for-dev" 2>/tmp/gh-err.txt; then
echo "::warning::Failed to remove ready-for-dev label:" >> "$GITHUB_STEP_SUMMARY"
cat /tmp/gh-err.txt >> "$GITHUB_STEP_SUMMARY"
fi
- name: Post feedback comment
if: >-
github.event.action == 'opened'
|| github.event.action == 'reopened'
|| (github.event.action == 'labeled' && github.event.label.name == 'ready-for-dev')
|| (steps.readiness.outputs.ready == 'true' && !contains(github.event.issue.labels.*.name, 'ready-for-dev'))
|| (steps.readiness.outputs.ready != 'true' && contains(github.event.issue.labels.*.name, 'ready-for-dev'))
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
if [ "${{ steps.readiness.outputs.ready }}" = "true" ]; then
node .github/scripts/post-readiness-comment.mjs \
--issue-number "${{ github.event.issue.number }}" \
--repo "${{ github.repository }}" \
--ready
else
node .github/scripts/post-readiness-comment.mjs \
--issue-number "${{ github.event.issue.number }}" \
--repo "${{ github.repository }}" \
--reasons-file "${{ steps.readiness.outputs.reasons_file }}"
fi