feat(workflows): add issue lifecycle with update mechanism#98
feat(workflows): add issue lifecycle with update mechanism#98MarkusNeusinger merged 4 commits intomainfrom
Conversation
…abels - Rename label sub-issue to plot-request:impl for clarity - Add update mechanism via [update] and [update:library] title syntax - Add targeted library regeneration (skip unaffected libraries) - Add new labels: test, update (completed already existed) - Update plot-update.yml template with new syntax and library dropdown - Document lifecycle and update workflow in CLAUDE.md and docs/workflow.md - Tag existing test issues (#33-37, #52, #75, #77-84) with test label
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
There was a problem hiding this comment.
Pull request overview
This PR adds an update mechanism for existing plot specifications and renames the sub-issue label to plot-request:impl for improved clarity. The update mechanism allows users to regenerate all implementations or target specific libraries using special issue title syntax ([update] or [update:library]). The implementation includes targeted library regeneration that conditionally runs generation jobs based on the specified library, along with comprehensive documentation of the new workflow and issue lifecycle.
- New update syntax:
[update] spec-idfor all libraries or[update:library] spec-idfor targeted regeneration - Label rename from
sub-issuetoplot-request:implfor library implementation tracking - New labels added:
test,update,completedwith documented lifecycle states - Conditional job execution to skip unaffected libraries during targeted updates
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 4 comments.
Show a summary per file
| File | Description |
|---|---|
.github/workflows/gen-new-plot.yml |
Adds update detection regex, spec ID extraction for updates, library targeting conditions for generation jobs, and label rename to plot-request:impl |
.github/workflows/bot-sync-status.yml |
Updates label check from sub-issue to plot-request:impl for consistency |
.github/ISSUE_TEMPLATE/plot-update.yml |
Complete template restructure with update-focused title format, library dropdown, and simplified change request fields |
docs/workflow.md |
Documents new label (plot-request:impl, completed, update, test) and adds update workflow section with examples |
CLAUDE.md |
Updates workflow status labels section and adds comprehensive update mechanism documentation with issue lifecycle diagrams |
Comments suppressed due to low confidence (1)
.github/workflows/gen-new-plot.yml:213
- The
create-sub-issuesjob creates sub-issues for ALL libraries regardless of whethertarget_libraryis specified. When a user creates an issue with[update:seaborn] scatter-basic, this will create 8 sub-issues but only run generation for seaborn, leaving 7 orphaned sub-issues in "generating" state.
Suggestion: Modify the loop to only create a sub-issue when target_library is empty OR matches the current library:
for LIBRARY in ${{ env.LIBRARIES }}; do
TARGET="${{ needs.check-conditions.outputs.target_library }}"
# Skip if targeting specific library and this isn't it
if [ -n "$TARGET" ] && [ "$TARGET" != "$LIBRARY" ]; then
continue
fi
echo "Creating sub-issue for $LIBRARY..."
# ... rest of the code
done - name: Create sub-issues for each library
id: create
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SPEC_ID="${{ needs.check-conditions.outputs.spec_id }}"
PARENT_NUM="${{ github.event.issue.number }}"
PARENT_NODE_ID=$(gh api repos/${{ github.repository }}/issues/$PARENT_NUM --jq '.node_id')
for LIBRARY in ${{ env.LIBRARIES }}; do
echo "Creating sub-issue for $LIBRARY..."
# Check if sub-issue already exists
EXISTING=$(gh issue list --label "library:$LIBRARY" --search "[$SPEC_ID] in:title" --json number -q '.[0].number' 2>/dev/null || echo "")
if [ -n "$EXISTING" ]; then
echo "${LIBRARY}_issue=$EXISTING" >> $GITHUB_OUTPUT
echo "::notice::Sub-issue for $LIBRARY already exists: #$EXISTING"
continue
fi
# Create sub-issue
SUB_BODY="## [$SPEC_ID] $LIBRARY Implementation
**Parent Issue:** #$PARENT_NUM
**Spec:** \`specs/$SPEC_ID.md\`
**Library:** $LIBRARY
---
### Attempt History
_Attempts will be documented below as comments._
"
SUB_ISSUE=$(gh issue create \
--title "[$SPEC_ID] $LIBRARY implementation" \
--body "$SUB_BODY" \
--label "library:$LIBRARY,plot-request:impl,generating")
SUB_NUM=$(echo "$SUB_ISSUE" | grep -oP '\d+$')
SUB_NODE_ID=$(gh api repos/${{ github.repository }}/issues/$SUB_NUM --jq '.node_id')
# Link as sub-issue using GitHub's sub-issues API
gh api graphql -f query='
mutation($parent: ID!, $child: ID!) {
addSubIssue(input: {issueId: $parent, subIssueId: $child}) {
issue { id }
}
}' -f parent="$PARENT_NODE_ID" -f child="$SUB_NODE_ID" 2>/dev/null || echo "Note: Sub-issue linking not available"
echo "${LIBRARY}_issue=$SUB_NUM" >> $GITHUB_OUTPUT
echo "::notice::Created sub-issue for $LIBRARY: #$SUB_NUM"
done
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
| label: Spec ID | ||
| description: "The spec ID of the plot to update (e.g., bar-basic)" | ||
| placeholder: "bar-basic" | ||
| description: "The spec ID of the plot to update (will be appended to title)" |
There was a problem hiding this comment.
The description states "will be appended to title" but GitHub issue templates don't automatically append form field values to the title. Users must manually type the spec ID into the title after the [update] prefix.
Suggestion: Update the description to be clearer:
description: "The spec ID of the plot to update (must be manually added to the title above)"| description: "The spec ID of the plot to update (will be appended to title)" | |
| description: "The spec ID of the plot to update (must be manually added to the title above)" |
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 6 out of 6 changed files in this pull request and generated 6 comments.
Comments suppressed due to low confidence (2)
.github/workflows/gen-new-plot.yml:213
- The
create-sub-issuesjob doesn't respect thetarget_libraryoutput and will create sub-issues for all 8 libraries even when[update:library]syntax is used. This means that if a user specifies[update:matplotlib] scatter-basic, sub-issues will be created for all libraries (seaborn, plotly, etc.), but only the matplotlib generation job will run.
Consider adding a condition to skip creating sub-issues for libraries that aren't targeted, or filter the loop in the "Create sub-issues for each library" step to only process the target library when specified.
-f content=eyes
- name: Add in-progress label
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
gh issue edit ${{ github.event.issue.number }} --add-label "in-progress"
- name: Create sub-issues for each library
id: create
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
SPEC_ID="${{ needs.check-conditions.outputs.spec_id }}"
PARENT_NUM="${{ github.event.issue.number }}"
PARENT_NODE_ID=$(gh api repos/${{ github.repository }}/issues/$PARENT_NUM --jq '.node_id')
for LIBRARY in ${{ env.LIBRARIES }}; do
echo "Creating sub-issue for $LIBRARY..."
# Check if sub-issue already exists
EXISTING=$(gh issue list --label "library:$LIBRARY" --search "[$SPEC_ID] in:title" --json number -q '.[0].number' 2>/dev/null || echo "")
if [ -n "$EXISTING" ]; then
echo "${LIBRARY}_issue=$EXISTING" >> $GITHUB_OUTPUT
echo "::notice::Sub-issue for $LIBRARY already exists: #$EXISTING"
continue
fi
# Create sub-issue
SUB_BODY="## [$SPEC_ID] $LIBRARY Implementation
**Parent Issue:** #$PARENT_NUM
**Spec:** \`specs/$SPEC_ID.md\`
**Library:** $LIBRARY
---
### Attempt History
_Attempts will be documented below as comments._
"
SUB_ISSUE=$(gh issue create \
--title "[$SPEC_ID] $LIBRARY implementation" \
--body "$SUB_BODY" \
--label "library:$LIBRARY,plot-request:impl,generating")
SUB_NUM=$(echo "$SUB_ISSUE" | grep -oP '\d+$')
SUB_NODE_ID=$(gh api repos/${{ github.repository }}/issues/$SUB_NUM --jq '.node_id')
# Link as sub-issue using GitHub's sub-issues API
gh api graphql -f query='
mutation($parent: ID!, $child: ID!) {
.github/workflows/gen-new-plot.yml:223
- [nitpick] In GitHub Actions, an empty string
''is falsy in conditional expressions. The condition checks iftarget_library == ''which will be true when no library is specified. However, when checking for a specific library match, you're comparing against the library name string directly.
This logic is correct, but consider using a more explicit check for clarity:
(needs.check-conditions.outputs.target_library == '' || needs.check-conditions.outputs.target_library == 'matplotlib')The current implementation works, but it's worth documenting that empty string is used to represent "all libraries" rather than using a special value like "all".
echo "::notice::Created sub-issue for $LIBRARY: #$SUB_NUM"
done
# ============================================================================
You can also share your feedback on Copilot code review for a chance to win a $100 gift card. Take the survey.
| if echo "$ISSUE_TITLE" | grep -qiP '^\[update(:[a-z]+)?\]'; then | ||
| IS_UPDATE="true" | ||
| # Extract target library if specified (e.g., [update:seaborn]) | ||
| TARGET_LIBRARY=$(echo "$ISSUE_TITLE" | grep -oiP '^\[update:\K[a-z]+(?=\])' | tr '[:upper:]' '[:lower:]' || echo "") |
There was a problem hiding this comment.
The regex pattern allows only lowercase letters [a-z]+ but library names in the codebase use lowercase only. However, the issue template dropdown includes library names like "matplotlib", "seaborn", etc., which users could manually type with different cases. While there's a tr '[:upper:]' '[:lower:]' to handle this, the regex should be more permissive to match the input before normalization.
Consider changing the pattern to: '^\[update:\K[a-zA-Z]+(?=\])' to accept any case, since you're already normalizing with tr '[:upper:]' '[:lower:]'.
| TARGET_LIBRARY=$(echo "$ISSUE_TITLE" | grep -oiP '^\[update:\K[a-z]+(?=\])' | tr '[:upper:]' '[:lower:]' || echo "") | |
| TARGET_LIBRARY=$(echo "$ISSUE_TITLE" | grep -oiP '^\[update:\K[a-zA-Z]+(?=\])' | tr '[:upper:]' '[:lower:]' || echo "") |
|
|
||
| To update or regenerate an existing plot: | ||
|
|
||
| 1. Create issue with title: `[update] {spec-id}` (all libraries) or `[update:seaborn] {spec-id}` (single library) |
There was a problem hiding this comment.
[nitpick] Inconsistency in example syntax: the documentation shows [update:library] but the example uses [update:seaborn] with a specific library name. While this works, it would be clearer to show the general pattern first, then the specific example.
Consider: [update:{library}] for the pattern, followed by the concrete example [update:seaborn].
| 1. Create issue with title: `[update] {spec-id}` (all libraries) or `[update:seaborn] {spec-id}` (single library) | |
| 1. Create issue with title: `[update] {spec-id}` (all libraries) or `[update:{library}] {spec-id}` (single library, e.g. `[update:seaborn] heatmap-correlation`) |
| IS_UPDATE="false" | ||
| TARGET_LIBRARY="" | ||
|
|
||
| if echo "$ISSUE_TITLE" | grep -qiP '^\[update(:[a-z]+)?\]'; then |
There was a problem hiding this comment.
The regex pattern '^\[update(:[a-z]+)?\]' should be more permissive to match any case in the library name since the code already normalizes the extracted library with tr '[:upper:]' '[:lower:]' on line 75.
Consider changing to: '^\[update(:[a-zA-Z]+)?\]' to accept mixed-case library names before normalization.
| if echo "$ISSUE_TITLE" | grep -qiP '^\[update(:[a-z]+)?\]'; then | |
| if echo "$ISSUE_TITLE" | grep -qiP '^\[update(:[a-zA-Z]+)?\]'; then |
| **Sub-Issue Lifecycle:** | ||
| ``` | ||
| [open] generating → testing → reviewing → merged [closed] | ||
| → not-feasible [closed] |
There was a problem hiding this comment.
[nitpick] The Sub-Issue Lifecycle documentation shows the transition to not-feasible but doesn't show the intermediate retry states (with ai-rejected label). According to the workflow files in the codebase, the actual flow includes retry attempts with ai-rejected before reaching not-feasible after 3 failures.
Consider updating to show:
[open] generating → testing → reviewing → merged [closed]
→ ai-rejected (retry) → ...
→ not-feasible [closed] (after 3 attempts)
| → not-feasible [closed] | |
| → ai-rejected (retry) → ... | |
| → not-feasible [closed] (after 3 attempts) |
| **Sub-Issue Lifecycle:** | ||
| ``` | ||
| [open] generating → testing → reviewing → merged [closed] | ||
| → not-feasible [closed] |
There was a problem hiding this comment.
[nitpick] The Sub-Issue Lifecycle documentation shows the transition to not-feasible but doesn't show the intermediate retry states (with ai-rejected label). According to the workflow files in the codebase, the actual flow includes retry attempts with ai-rejected before reaching not-feasible after 3 failures.
Consider updating to show:
[open] generating → testing → reviewing → merged [closed]
→ ai-rejected (retry) → ...
→ not-feasible [closed] (after 3 attempts)
| → not-feasible [closed] | |
| → ai-rejected (retry) → ... | |
| → not-feasible [closed] (after 3 attempts) |
Summary
sub-issue→plot-request:implfor clarity[update]and[update:library]title syntaxtest,update,completedChanges
New Update Syntax
[update] scatter-basic→ Regenerate all 8 libraries[update:seaborn] scatter-basic→ Regenerate only seabornIssue Lifecycle
New Labels
test- Test issues excluded from production searchesupdate- Update request for existing speccompleted- All implementations mergedFiles Changed
.github/workflows/gen-new-plot.yml- Update detection + targeted generation.github/workflows/bot-sync-status.yml- Label rename.github/ISSUE_TEMPLATE/plot-update.yml- New syntax + library dropdownCLAUDE.md- Labels + lifecycle documentationdocs/workflow.md- Labels + update workflow documentationTest plan
[update] line-basicissue and verify only generation jobs run[update:matplotlib] line-basicand verify only matplotlib job runsis:issue label:plot-request -label:testsearch