mirror of
https://github.com/github/gh-stack.git
synced 2026-09-14 20:26:28 +08:00
d2a390f2ff
The `link` command previously allowed PRs in any state to be added to a
stack, including PRs that had already been merged, were closed, were
sitting in a merge queue, or had auto-merge enabled. Adding such PRs to
a stack is invalid because they have already been or will soon be merged,
which breaks the stacked PR workflow.
Add a new validation phase (Phase 2b) to `runLink` that checks the
eligibility of every existing PR found during lookup, before any new PRs
are created or stack operations are performed. Only open/draft PRs
without auto-merge enabled are eligible. All ineligible PRs are reported
at once with a clear per-PR error message indicating the specific reason
(merged, closed, in merge queue, or auto-merge enabled).
Changes:
internal/github/github.go:
- Add AutoMergeRequest struct and field on PullRequest
- Add IsAutoMergeEnabled() method on *PullRequest
- Update FindPRByNumber and FindPRForBranch GraphQL queries to fetch
the autoMergeRequest field
internal/github/github_test.go:
- Add TestPullRequest_IsAutoMergeEnabled (nil, non-nil, nil receiver)
cmd/link.go:
- Add pr field to resolvedArg to retain full PR data from lookup
- Add validatePREligibility() that rejects merged/closed/queued/
auto-merge-enabled PRs with descriptive error messages
- Wire validation into runLink between PR lookup and stack operations
cmd/link_test.go:
- Add 7 tests covering each disallowed state by PR number and branch
name, plus a multi-invalid-PR reporting test
83 lines
2.1 KiB
Go
83 lines
2.1 KiB
Go
package github
|
|
|
|
import (
|
|
"testing"
|
|
|
|
graphql "github.com/cli/shurcooL-graphql"
|
|
"github.com/stretchr/testify/assert"
|
|
)
|
|
|
|
func TestPRURL(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
host string
|
|
owner string
|
|
repo string
|
|
number int
|
|
want string
|
|
}{
|
|
{"github.com", "github.com", "owner", "repo", 42, "https://github.com/owner/repo/pull/42"},
|
|
{"GHES host", "ghes.example.com", "myorg", "myrepo", 99, "https://ghes.example.com/myorg/myrepo/pull/99"},
|
|
{"empty host defaults to github.com", "", "owner", "repo", 1, "https://github.com/owner/repo/pull/1"},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
got := PRURL(tt.host, tt.owner, tt.repo, tt.number)
|
|
assert.Equal(t, tt.want, got)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestPullRequest_IsQueued(t *testing.T) {
|
|
t.Run("not queued when MergeQueueEntry is nil", func(t *testing.T) {
|
|
pr := &PullRequest{Number: 1}
|
|
assert.False(t, pr.IsQueued())
|
|
})
|
|
|
|
t.Run("queued when MergeQueueEntry has ID", func(t *testing.T) {
|
|
pr := &PullRequest{
|
|
Number: 1,
|
|
MergeQueueEntry: &MergeQueueEntry{ID: "MQE_123"},
|
|
}
|
|
assert.True(t, pr.IsQueued())
|
|
})
|
|
|
|
t.Run("nil receiver is safe", func(t *testing.T) {
|
|
var pr *PullRequest
|
|
assert.False(t, pr.IsQueued())
|
|
})
|
|
}
|
|
|
|
func TestPullRequest_IsAutoMergeEnabled(t *testing.T) {
|
|
t.Run("not enabled when AutoMergeRequest is nil", func(t *testing.T) {
|
|
pr := &PullRequest{Number: 1}
|
|
assert.False(t, pr.IsAutoMergeEnabled())
|
|
})
|
|
|
|
t.Run("enabled when AutoMergeRequest is present", func(t *testing.T) {
|
|
pr := &PullRequest{
|
|
Number: 1,
|
|
AutoMergeRequest: &AutoMergeRequest{EnabledAt: "2024-01-01T00:00:00Z"},
|
|
}
|
|
assert.True(t, pr.IsAutoMergeEnabled())
|
|
})
|
|
|
|
t.Run("nil receiver is safe", func(t *testing.T) {
|
|
var pr *PullRequest
|
|
assert.False(t, pr.IsAutoMergeEnabled())
|
|
})
|
|
}
|
|
|
|
func TestToGraphQLInt(t *testing.T) {
|
|
t.Run("in range", func(t *testing.T) {
|
|
got, err := toGraphQLInt(123)
|
|
assert.NoError(t, err)
|
|
assert.Equal(t, graphql.Int(123), got)
|
|
})
|
|
|
|
t.Run("out of range", func(t *testing.T) {
|
|
_, err := toGraphQLInt(1 << 40)
|
|
assert.Error(t, err)
|
|
})
|
|
}
|