Rework ref usage when finding and creating PRs#10621
Conversation
f8e918b to
67d2c76
Compare
jtmcg
left a comment
There was a problem hiding this comment.
I definitely like the direction this is headed
andyfeller
left a comment
There was a problem hiding this comment.
All in all, I love the changes! I haven't dug into how these affect gh pr view yet but I don't see any major blocking concerns with proceed ✨
67d2c76 to
055f2e0
Compare
c1dfebb to
95ecc45
Compare
| @@ -1,4 +1,4 @@ | |||
| skip 'it creates a fork owned by the user running the test' | |||
| #skip 'it creates a fork owned by the user running the test' | |||
There was a problem hiding this comment.
Will revert all these skips these when I'm done.
95ecc45 to
7ce312f
Compare
andyfeller
left a comment
There was a problem hiding this comment.
Just doing a partial review of pkg/cmd/pr packages focused on create, finder, find_refs_resolution by request
tldr: I think these new types / constructs make the code easier to understand. Leaving a variety of questions / nits but nothing to detract or pump the brakes
| QualifiedHeadRef() string | ||
| UnqualifiedHeadRef() string |
There was a problem hiding this comment.
question: how would you explain the difference between qualified and unqualified and which would an contributor or maintainer should use for a given purpose?
There was a problem hiding this comment.
Good question, it is a challenging distinction and different between the find and the create. The finder uses the Unqualified form to work with the API, and then uses the Qualified form to match on the returned Pull Requests. The create uses the Qualified form with the API. Unqualified is often used with git, Qualified is often used with UI messages.
andyfeller
left a comment
There was a problem hiding this comment.
Truly a major effort! There are no major blockers to merging this and finishing the the original PR aside from a few nits.
| # Assert that the PR was created with the correct head repository and refs | ||
| exec gh pr status | ||
| ! stdout 'There is no pull request associated with' |
There was a problem hiding this comment.
So to be clear, the name of this acceptance test is about gh pr status being able to locate the pull request that crosses the user fork-to-upstream relationship, correct?
Beyond the fact that we're using an organization for acceptance testing, would this also work if we tested against a user owned repository rather than an organization?
There was a problem hiding this comment.
So to be clear, the name of this acceptance test is about gh pr status being able to locate the pull request that crosses the user fork-to-upstream relationship, correct?
Yes. Sorry, I should have linked that this PR also fixes #10644
would this also work if we tested against a user owned repository rather than an organization?
The test clones into a user namespace, so I think maybe you've got this inverted? I would not expect it to work for orgs, which we know doesn't work correctly with the ref format :
| cs.Register(`git show-ref --verify -- HEAD refs/remotes/origin/feature`, 1, "") | ||
| cs.Register("git show-ref --verify -- HEAD refs/remotes/origin/feature", 1, "") |
There was a problem hiding this comment.
question: are the multiple calls from trying to determine tracking ref? shouldn't this only be called once?
Wondering why we're registering the same git show-ref command twice, I was trying to trace the code to answer the question myself, but not sure why. 🤔
question: is there a reason to mix raw strings and double quoted strings?
Just trying to following the trail:
cli/pkg/cmd/pr/create/create.go
Lines 574 to 579 in ce4f5c5
cli/pkg/cmd/pr/create/create.go
Lines 688 to 692 in ce4f5c5
cli/pkg/cmd/pr/create/create.go
Lines 266 to 267 in ce4f5c5
There was a problem hiding this comment.
question: are the multiple calls from trying to determine tracking ref? shouldn't this only be called once?
I think this is explained in the comments here:
cli/pkg/cmd/pr/create/create.go
Lines 783 to 816 in bee6278
TL;DR: if we think we found the repo from git, but it's not on the correct ref, we fall back to guessing. There is a bug in the previous code that makes reuse in both cases wrong. It can be fixed, but I didn't want to expand the scope of changes just to rarely avoid calling show refs twice.
question: is there a reason to mix raw strings and double quoted strings?
Copy and pasting from places that were using heredoc. I'll make them consistent.
| // When the command is run | ||
| reg := &httpmock.Registry{} | ||
| reg.StubRepoInfoResponse("OWNER", "REPO", "master") | ||
| defer reg.Verify(t) | ||
|
|
||
| reg.Register( | ||
| httpmock.GraphQL(`mutation PullRequestCreate\b`), | ||
| httpmock.GraphQLMutation(` | ||
| { "data": { "createPullRequest": { "pullRequest": { | ||
| "URL": "https://github.com/OWNER/REPO/pull/12" | ||
| } } } }`, func(input map[string]interface{}) { | ||
| assert.Equal(t, "REPOID", input["repositoryId"].(string)) | ||
| assert.Equal(t, "master", input["baseRefName"].(string)) | ||
| assert.Equal(t, "OTHEROWNER:feature", input["headRefName"].(string)) | ||
| })) |
There was a problem hiding this comment.
note: while following this test, I just wanted to permalink to StubRepoInfoResponse source which is responsible for sourcing these assertion values in order to make sure I was following along
Lines 9 to 23 in ce4f5c5
There was a problem hiding this comment.
Yeh it's spooky action at a distance.
| } | ||
| } | ||
|
|
||
| func TestPRFindRefs(t *testing.T) { |
There was a problem hiding this comment.
thought: would love discussing the various architecture approaches to tests like this at some point.
this 1 test contains multiple, parallel test runs including a table-driven test. it makes me step by and wonder the benefits and trade offs to the different approaches, wondering when we choose which.
There was a problem hiding this comment.
Sure. Strong opinion: Tests that don't share the same assertions shouldn't be tabled together. Weak opinion: Subtests allow for nice behavioural descriptions compared to top level tests. Not much more than that.
jtmcg
left a comment
There was a problem hiding this comment.
Woo! Good work on this. I appreciate where this went and all the heavy lifting you've done. I think only one of my comments is really actionable, but otherwise I'm happy with this. Don't let me be a blocker to others giving this a ✅
Co-authored-by: Andy Feller <[email protected]>
Co-authored-by: Andy Feller <[email protected]>
Co-authored-by: Andy Feller <[email protected]>
8b67d4e
into
kw/575-detect-push-target-for-local-branches-without-upstream-configuration
Description
Relates to #575
Will also fix: #10644
In reviewing #10513 I found it extremely hard to have confidence. Fundamentally, carrying various forms of potentially illegal state representations around, doing conditional checks everywhere, and splitting and concatenating strings is very challenging.
I decided I really, really wanted to encode the valid states where possible in the type system. So for example, instead of having a boolean "isPushEnabled" toggled on and off throughout various conditional behaviour, we collect it all into a
skipPushRefstype that has only the information required.I've made liberal use of
o.Optionto indicate when something is optional. Yes, it's possible to put anilinside ano.Option[ghrepo.Interface]and we don't check for that, which might lead to bugs, but I the approach is still a significant improvement overnilchecks everywhere which convey absolutely nothing about the intended optionality of a piece of data.Finally, I wasted a lot of time trying to converge the refs between create and find, and it didn't work out at all. Fundamentally the acceptable data for each operation varies (
createneeds baseRepo, baseBranch, qualifiedHeadRef, maybe a head repo for push, whilefindneedsbaseRepo,qualifiedHeadRef, optionally abaseBranchand no head repo). Trying to share these data structures resulted in marking lots of data as optional, which just brought back the original problem of the compiler being unable to help.In some cases I have left behaviour as it used to be even if (or because) I didn't fully understand it, or because changing it would expand an already very large PR for less value. I have left comments in these cases.
As of writing, this passes all the Pull Request A/C tests.
Reviewer Notes
It's probably better to read the files top to bottom rather than trying to work the diffs. It might even make more sense to compare to current trunk rather than the PR this is on top of.
I would be surprised even with all this work if we didn't have bugs after shipping. My hope is that bugs will be easier to ferret out and fix in a sustainable manner going forwards, rather than there being no bugs.
Sorry.