Skip to content

Conversation

@jacob314
Copy link
Contributor

@jacob314 jacob314 commented Jan 21, 2026

Summary

Script to add the correct area label and type to all sub-issues of an issue.
This recursively

Details

Example usage:
scripts/cascade_area.sh google-gemini 33 14411

Also fills out the type field if it is missing defaulting to Task as that is a reasonable default for sub-issues that are missing a type.

@jacob314 jacob314 requested a review from a team as a code owner January 21, 2026 23:24
@gemini-code-assist
Copy link
Contributor

Summary of Changes

Hello @jacob314, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request introduces a new shell script designed to streamline the management of GitHub ProjectV2 boards. The script automates the process of inheriting specific field values, such as 'Area,' from a parent issue to all its associated sub-issues and tracked issues. Additionally, it ensures that these descendant issues are consistently marked with a 'Ready' status and 'Task' type, enhancing project consistency and reducing manual effort in project curation.

Highlights

  • New Script for Project Curation: A new cascade_area.sh script has been added to automate the curation of GitHub ProjectV2 boards, specifically for cascading field values.
  • Cascading Field Values: The script propagates a specified field's value (defaulting to 'Area') from a parent issue to all its linked descendants (tracked issues and sub-issues) within a project board.
  • Automated Status and Type Updates: Descendant issues found by the script are automatically set to 'Ready' status and 'Task' type if these fields are not already defined on the project board item.
  • Support for Org and User Projects: The script is designed to identify and operate on both organization-level and user-level GitHub ProjectV2 boards.
  • Dynamic Project Item Addition: If a descendant issue is not already present on the target project board, the script will add it before attempting to update its fields.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Contributor

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request introduces a new bash script, scripts/cascade_area.sh, to automate the process of cascading a project field value from a parent issue to its descendants. The script is well-structured and handles argument parsing and error conditions appropriately.

However, I've identified two major performance issues that should be addressed:

  1. Critical Performance Bottleneck: The script makes a large number of sequential API calls within a loop to update each descendant issue. This will be very slow and may hit API rate limits for issue trees of even moderate size. I've recommended refactoring this to use GraphQL query aliasing to batch-read data for all descendants in a single API call.
  2. Inefficient Search Algorithm: The Breadth-First Search (BFS) used to find descendants uses an O(N) array search to check for already visited issues, leading to an overall O(N^2) complexity. I've suggested using a bash associative array for an O(1) lookup, which will significantly speed up this part of the script.

Addressing these points will make the script much more scalable and robust.

Comment on lines +233 to +328
for ISSUE_ID in "${DESCENDANTS[@]}"; do
# We need the Project Item ID for this specific issue, and check its Type
ITEM_DATA=$(gh api graphql -f issueId="$ISSUE_ID" -f query='
query($issueId: ID!) {
node(id: $issueId) {
... on Issue {
number
projectItems(first: 10) {
nodes {
id
project { id }
fieldValueByName(name: "Type") {
... on ProjectV2ItemFieldSingleSelectValue {
name
}
}
}
}
}
}
}
')

ITEM_ID=$(echo "$ITEM_DATA" | jq -r --arg pid "$PROJECT_ID" '.data.node.projectItems.nodes[]? | select(.project.id == $pid) | .id // empty')
ISSUE_NUM=$(echo "$ITEM_DATA" | jq -r '.data.node.number')

# Check if Type (Issue Type) is already set
# We check the issueType field on the issue
CURRENT_ISSUE_TYPE=$(gh api graphql -f issueId="$ISSUE_ID" -f query='
query($issueId: ID!) {
node(id: $issueId) {
... on Issue {
issueType { name }
}
}
}
')
HAS_TASK_TYPE=$(echo "$CURRENT_ISSUE_TYPE" | jq -r '.data.node.issueType.name // empty')

if [ -z "$ITEM_ID" ]; then
echo "➕ Adding Issue #$ISSUE_NUM to project board..."
ADD_ITEM_DATA=$(gh api graphql -f projectId="$PROJECT_ID" -f contentId="$ISSUE_ID" -f query='
mutation($projectId: ID!, $contentId: ID!) {
addProjectV2ItemById(input: {projectId: $projectId, contentId: $contentId}) {
item { id }
}
}
')
ITEM_ID=$(echo "$ADD_ITEM_DATA" | jq -r '.data.addProjectV2ItemById.item.id // empty')
fi

if [ -n "$ITEM_ID" ]; then
echo "✏️ Updating Issue #$ISSUE_NUM (Item: $ITEM_ID)..."

# Update Area
gh api graphql -f projectId="$PROJECT_ID" -f itemId="$ITEM_ID" -f fieldId="$FIELD_ID" -f optionId="$PARENT_OPTION_ID" -f query='
mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
updateProjectV2ItemFieldValue(input: {
projectId: $projectId
itemId: $itemId
fieldId: $fieldId
value: { singleSelectOptionId: $optionId }
}) { clientMutationId }
}
' > /dev/null

# Update Status to Ready if we found the IDs
if [ -n "$STATUS_FIELD_ID" ] && [ -n "$READY_OPTION_ID" ]; then
echo " └─ Setting Status to Ready..."
gh api graphql -f projectId="$PROJECT_ID" -f itemId="$ITEM_ID" -f fieldId="$STATUS_FIELD_ID" -f optionId="$READY_OPTION_ID" -f query='
mutation($projectId: ID!, $itemId: ID!, $fieldId: ID!, $optionId: String!) {
updateProjectV2ItemFieldValue(input: {
projectId: $projectId
itemId: $itemId
fieldId: $fieldId
value: { singleSelectOptionId: $optionId }
}) { clientMutationId }
}
' > /dev/null
fi

# Update Issue Type to Task if empty
if [ -n "$TASK_TYPE_ID" ] && [ -z "$HAS_TASK_TYPE" ]; then
echo " └─ Setting Issue Type to 'Task'..."
gh api graphql -f issueId="$ISSUE_ID" -f issueTypeId="$TASK_TYPE_ID" -f query='
mutation($issueId: ID!, $issueTypeId: ID!) {
updateIssue(input: {id: $issueId, issueTypeId: $issueTypeId}) {
issue { issueType { name } }
}
}
' > /dev/null
fi
else
echo "❌ Failed to add/find Issue #$ISSUE_NUM on the project board."
fi
done
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

critical

This loop iterates through all descendant issues and makes multiple sequential API calls for each one. For an issue tree with N descendants, this can result in up to 6*N API calls (getItem, getType, addItem, updateArea, updateStatus, updateType). This is highly inefficient, will be very slow for a large number of issues, and increases the risk of hitting GitHub API rate limits.

To make this more efficient, you should batch these operations. The GitHub GraphQL API is well-suited for this:

  1. Batch Read Operations: After collecting all DESCENDANTS IDs, use a single GraphQL query with aliases to fetch all the necessary information (projectItems, issueType, etc.) for all descendants at once. This reduces N or 2N read calls to a single call.

    Example of a batched query:

    query getIssueData($id1: ID!, $id2: ID!) {
      issue1: node(id: $id1) { ... on Issue { number projectItems(first:10){...} } }
      issue2: node(id: $id2) { ... on Issue { number projectItems(first:10){...} } }
    }
  2. Process Data: Process the single large JSON response in your script to determine which issues need to be added to the project and which fields need updating.

  3. Execute Mutations: While mutations are harder to batch, you will still have significantly reduced the total number of API calls by batching the reads. You can then loop through and execute the necessary mutations.

This architectural change is critical for the script to be scalable and reliable.

for child in $CHILD_IDS; do
if [ -z "$child" ] || [ "$child" == "null" ]; then continue; fi
# Check if seen (simple duplicate check)
if [[ ! " ${SEEN[@]} " =~ " ${child} " ]]; then
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

high

The current method to check if a child issue has been seen ([[ ! " ${SEEN[@]} " =~ " ${child} " ]]) has a time complexity of O(N), where N is the number of items in the SEEN array. Since this check is inside a loop, the overall complexity for finding unique descendants becomes O(M^2) where M is the total number of descendants. This can become very slow if the issue tree is large.

For better performance, consider using a bash associative array (available in bash 4.0+) for the SEEN set. This provides an average time complexity of O(1) for lookups.

Here's how you could refactor it:

  1. Initialize SEEN as an associative array (this would modify line 185):
declare -A SEEN
SEEN["$ROOT_NODE_ID"]=1
  1. Update the check and addition within the loop (this would replace lines 219-226):
if [[ -z "${SEEN[$child]}" ]]; then
  SEEN["$child"]=1
  QUEUE+=("$child")
  DESCENDANTS+=("$child")
  # Extract number just for logging
  CHILD_NUM=$(echo "$CHILDREN_JSON" | jq -r --arg cid "$child" '((.data.node.trackedIssues.nodes[]? | select(.id == $cid) | .number) // (.data.node.subIssues.nodes[]? | select(.id == $cid) | .number))')
  echo "   Found descendant: #$CHILD_NUM"
fi

This change will significantly improve the script's performance for projects with many interconnected issues. Note that this requires bash version 4.0 or newer.

@github-actions
Copy link

Size Change: -2 B (0%)

Total Size: 23.2 MB

ℹ️ View Unchanged
Filename Size Change
./bundle/gemini.js 23.1 MB -2 B (0%)
./bundle/sandbox-macos-permissive-closed.sb 1.03 kB 0 B
./bundle/sandbox-macos-permissive-open.sb 890 B 0 B
./bundle/sandbox-macos-permissive-proxied.sb 1.31 kB 0 B
./bundle/sandbox-macos-restrictive-closed.sb 3.29 kB 0 B
./bundle/sandbox-macos-restrictive-open.sb 3.36 kB 0 B
./bundle/sandbox-macos-restrictive-proxied.sb 3.56 kB 0 B

compressed-size-action

@gemini-cli gemini-cli bot added the priority/p1 Important and should be addressed in the near term. label Jan 21, 2026
@jacob314 jacob314 removed the priority/p1 Important and should be addressed in the near term. label Jan 21, 2026
@jacob314 jacob314 changed the title Script to cascade areas when curating projects Script to cascade the Area field from an issue to subissues to help build projects Jan 21, 2026
@gemini-cli gemini-cli bot added the status/need-issue Pull requests that need to have an associated issue. label Jan 21, 2026
@gemini-cli
Copy link
Contributor

gemini-cli bot commented Jan 27, 2026

Hi there! Thank you for your contribution to Gemini CLI.

To improve our contribution process and better track changes, we now require all pull requests to be associated with an existing issue, as announced in our recent discussion and as detailed in our CONTRIBUTING.md.

This pull request is being closed because it is not currently linked to an issue. Once you have updated the description of this PR to link an issue (e.g., by adding Fixes #123 or Related to #123), it will be automatically reopened.

How to link an issue:
Add a keyword followed by the issue number (e.g., Fixes #123) in the description of your pull request. For more details on supported keywords and how linking works, please refer to the GitHub Documentation on linking pull requests to issues.

Thank you for your understanding and for being a part of our community!

@gemini-cli gemini-cli bot closed this Jan 27, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status/need-issue Pull requests that need to have an associated issue.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant