Skip to content

create-issues: set board Status (and Priority/Size) on added items #1

@lipex360x

Description

@lipex360x

Goal

create-issues adds each new issue to the linked Projects v2 board but leaves the Status field empty, so every card lands in "No Status" (outside every column). Set a default Status (and map the P* and size labels to the Priority/Size fields) when adding an item, so cards land categorized.

Symptom

After gh-toolkit create-issues <owner/repo> <issues.json> on a repo linked to a board, the issues appear as board items but all sit under "No Status". The Priority and Size single-select fields are also empty, even though the issue labels carry that data (P0, M, etc).

Reproduced on lipex360x/ledgerflow (2026-06-06): 8 issues created, all 8 in "No Status", Priority/Size blank.

Root cause

scripts/create-issues.sh, function add_to_board() (around lines 104-118): it runs the addProjectV2ItemById mutation but pipes the result to /dev/null, discarding the returned item.id. It never calls updateProjectV2ItemFieldValue, so no field is set. The item is added with empty Status/Priority/Size.

Fix path (chosen)

Extend add_to_board() (or add a sibling set_board_fields()):

  1. Capture the item.id returned by addProjectV2ItemById (stop discarding it).
  2. Query the linked project once for the Status, Priority, Size single-select field ids and their option ids (GraphQL projectV2.fields -> ProjectV2SingleSelectField). Cache for the run.
  3. Set Status to Backlog via updateProjectV2ItemFieldValue.
  4. Map the issue's labels to fields, best-effort: P0|P1|P2 -> Priority; XS|S|M|L|XL -> Size.
  5. Best-effort and idempotent: if a field or option does not exist on that project, skip it silently (a project without a Size field must not break). Keep board work non-fatal to the exit code, matching the current contract (issue creation is the primary contract).

Default Status is Backlog (the entry column). Rejected alternative: leaving Status configurable via a flag now. That is scope creep; a fixed Backlog default solves the reported bug, and a --default-status flag can be a later issue if needed.

Implementation order (TDD)

Tests are bats with a PATH-injected gh mock (per this repo's CLAUDE.md). Land as separate commits. Use chained assertions (&& \).

  1. Red - in tests/create-issues.bats, extend the gh mock to record GraphQL mutation calls to a log file, and add a test asserting that after create-issues, the recorded calls include an updateProjectV2ItemFieldValue setting Status to the Backlog option for the created item. Commit: test: create-issues sets board Status (failing). Confirm it fails because no such mutation is issued today (not a mock wiring error).
  2. Green - implement field-setting in create-issues.sh until the test passes. Add the Priority/Size mapping with their own assertions. Commit: feat: create-issues sets Status/Priority/Size on board items.
  3. Refactor - extract the field-resolution helper if it bloats add_to_board; keep tests green. Commit: refactor: extract board field resolution.

Also extend the dry-run so the omission is visible in preview (see AC): the dry-run currently exits before any board logic (lines 66-73) and prints only DRY_RUN:issue/<title>. Make it also print the intended fields, for example DRY_RUN:issue/<title>:status=Backlog,priority=P0,size=M.

Files to touch

File What changes
scripts/create-issues.sh capture item id; resolve field/option ids; set Status + map Priority/Size; extend dry-run output
tests/create-issues.bats mock records GraphQL mutations; assert Status/Priority/Size set; assert dry-run prints intended fields
README.md document board field behaviour
SKILL.md note that create-issues sets Status=Backlog and maps Priority/Size

Acceptance criteria

Tick each item by editing this issue body (gh issue edit 1) as you land the corresponding commit. Do not batch ticks at the end.

  • Created issues land in the Backlog column, not "No Status"
  • P0/P1/P2 labels set the board Priority field; XS..XL set Size
  • Missing field or option on a project is skipped silently (no failure, no exit-code change)
  • Dry-run prints the intended fields per issue (for example DRY_RUN:issue/<title>:status=Backlog,priority=P0,size=M)
  • Regression test was written red first and now passes
  • Board work stays non-fatal: a field-set failure logs a WARN to stderr and does not change the exit code
  • Quality gates pass: bats tests/; chained-assert audit prints nothing; shellcheck -x install.sh scripts/*.sh lib/*.sh bin/gh-toolkit tests/*.bats clean

Out of scope

  • A configurable --default-status flag (separate issue if wanted).
  • Backfilling Status on issues created before this fix (one-off, not part of the script contract).
  • Changing the shared single "Board" project model.

Constraints (from this repo's conventions)

  • Bash 3.2 compatible: guard array access with ${#arr[@]} before iterating.
  • Output contract: any FAILED line goes to stdout; logs and WARN go to stderr via log::*.
  • Bats: chain assertions with && \; keep setup statements unchained.
  • Never use --no-verify. Never add a non-bash runtime.

Branch

git checkout main && git pull
git checkout -b fix/board-status-fields-1

Open the PR with Closes #1.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions