diff --git a/bin/gs b/bin/gs index 9b085f4..6f869ed 100755 --- a/bin/gs +++ b/bin/gs @@ -24,8 +24,9 @@ gs - gentle-shell on main, plus one disposable worktree per PR gs pr [repo] One step to review PR : worktree (reused and updated if it exists), then Pi on it for shell PRs gs issue [repo] One step to start issue : race check (stops if the - issue is closed, assigned, or referenced by a PR; GS_FORCE=1 - skips it), branch /- from origin/main, + issue is closed, assigned to someone other than you, + or referenced by a PR; GS_FORCE=1 skips it), + branch /- from origin/main, then Pi on it for shell issues gs new New branch from fresh origin/main @@ -231,7 +232,11 @@ cmd_issue() { fi if [ "${GS_FORCE:-}" != 1 ]; then [ "$state" = OPEN ] || die "$gh_repo#$NUM is $state (GS_FORCE=1 to continue)" - [ -z "$assignees" ] || die "$gh_repo#$NUM is assigned to $assignees (GS_FORCE=1 to continue)" + # Your own assignment is your claim, not a race: only others block. + local me others="" + me=$(gh api user --jq .login 2>/dev/null || true) + others=$(printf '%s' "$assignees" | tr ',' '\n' | grep -vxF -- "${me:-}" | paste -sd, - || true) + [ -z "$others" ] || die "$gh_repo#$NUM is assigned to $others (GS_FORCE=1 to continue)" prs=$(gh pr list -R "$gh_repo" --state all --search "$NUM in:title,body" --json number,state,title \ --jq '.[] | " #\(.number) \(.state) \(.title)"') [ -z "$prs" ] || die "PRs may already reference #$NUM (GS_FORCE=1 to continue): diff --git a/tests/gs_test.sh b/tests/gs_test.sh index 18adb46..a80a96d 100755 --- a/tests/gs_test.sh +++ b/tests/gs_test.sh @@ -144,6 +144,32 @@ check "workshop: gs issue reuses the worktree and opens it isolated, never --lin check "workshop: gs issue kickoff names the cortex skill without a legacy home path" \ '[[ "$L" == *"cortex-maintainer-delivery skill"* ]] && [[ "$L" != *".pi/agent"* ]]' +# gs issue race check: only someone else's assignment blocks a new worktree. +race_stub() { + cat > "$S/gh" <> "$CALLS" ;; +esac +exit 0 +EOF + chmod +x "$S/gh" +} +setup workshop; race_stub me +OUT=$("$GS" issue shell 9 2>&1); L=$(cat "$CALLS" 2>/dev/null) +check "workshop: gs issue assigned only to you passes the race check" \ + '[[ "$OUT" != *"is assigned"* ]] && [[ "$L" == *"pr list"* ]]' +setup workshop; race_stub other +OUT=$("$GS" issue shell 9 2>&1); rc=$? +check "workshop: gs issue assigned to someone else still stops" \ + '[ "$rc" = 1 ] && [[ "$OUT" == *"#9 is assigned to other (GS_FORCE=1 to continue)"* ]]' +setup workshop; race_stub me,other +OUT=$("$GS" issue shell 9 2>&1); rc=$? +check "workshop: gs issue shared with someone else stops and names only them" \ + '[ "$rc" = 1 ] && [[ "$OUT" == *"#9 is assigned to other (GS_FORCE=1 to continue)"* ]]' + # --- sync (workshop) ---------------------------------------------------------- setup workshop