How to use `spr diff` from a fork?
joneshf opened this issue · comments
Is it currently possible to use spr diff
from a fork and have it create a PR in the upstream repo? I didn't see any options that seemed to imply it was possible, but I might be missing something in the way it works. If it's not possible, are there any thoughts on how it would work? I imagine this doesn't line up with anything in arcanist
, since as far as I know Phabricator is meant to be used with a single repo rather than with a bunch of forks.
From what I can understand, it looks like spr
uses octocrab
for interactions with the GitHub API, and it seems that PullRequestHandler.create
wants you to pass in a stringified representation of the fork in the head
if creating a pull request from a fork. For instance, if I had a fork of this repo at joneshf/spr
, was working on a branch named some-branch-name
, and I wanted to submit a PR from a fork of this repo, head
seems like it would be "joneshf:some-branch-name"
(assuming I understand the documentation of octocrab
correctly).
One idea could be to take an option on spr diff
specifying which repo to open the PR against. Maybe a better idea is to have a repo-wide configuration to specify if it's a fork or not? I guess it would depend on what else needs to know if it's a fork or not. But I get the feeling that the 80/20 here is: 80% of the time people are either always working directly against the origin repo (so not a fork) or they're always opening PRs against the upstream repo (so always a fork of the same repo), and 20% of the time you're doing something different (like opening a PR against a different repo that is neither upstream nor origin). So maybe most of the ask can be implemented with a repo-wide configuration? Maybe there's another idea?
In any case, I don't have any strong requirements here. I was just thinking about this because I was considering offering to implement something in this repo, and was going to try using spr
to do it, but then realized that I couldn't figure out how to create a PR from a fork. I figured Id just ask to see if it was already being thought about.
You're right, spr doesn't support this at this moment. But it sounds like a good addition, and it shouldn't be super hard.
Thinking about it, the first idea that comes to my mind would be to basically work with two remotes, e.g. origin
(which would be your fork) and upstream
(which would be the forked repo). When you make a local commit, it would be with the goal of merging it into upstream. When spr creates a GitHub-side branch, that would have to be on the origin
remote (i.e. your fork). So all the pushing would happen to origin
, and the API calls for creating a PR would have to be modified to reflect this situation, like you were saying.
I guess in most fork situations, it's the maintainers of the original repo who do the merging, so spr land
might not work for the PR author. But if you (or to be precise, the PAT that you give spr) has the power to make the API call to merge the PR, then I guess spr land
would need only minimal modification to allow you to do that.
I'm just thinking out loud here, but yeah, I think that should totally work.
spr as it is now is of course a little bit tailored towards our workflow here at Cord, but I would be happy to generalise it a bit more.
So in this workflow you'd go by the actual remotes named origin
/upstream
in the repo? Or would it be a config like other things for spr
. E.g. git config spr.origin …
/git config spr.upstream …
? Either way, I think if the upstream falls back to origin (so it still works if you don't have a fork) what you laid out makes sense.
As an aside, I think this is one of the things that would help tools like spr
(see also Graphite) become more wide-spread: being able to use it for typical open source contributions on GitHub. Using these stacked diff tools on a team is nice. But exposing more people to the workflow that didn't luck out and run into a team that uses this workflow I think is the thing that will be the tipping point.
There is spr.githubRemoteName
already, which is typically set to origin
. So it would be a good idea to have a config variable for the fork's remote name, and if not set, it's the same as spr.githubRemoteName
.
Completely agree with this helping adoption. Would be quite nice if external contributors to spr could use some to create and update their pull requests. They typically wouldn't be able to spr land
them, but that could be done by the maintainers. By the way, you can infact very easily land someone else's PR: e.g. spr patch 123 && spr land
.
I wanted to work on this, but my computer's been messing up pretty bad lately. Hopefully it gets fixed long enough to do some actual work, but don't wait for me to actually implement something here. I'm going to catalogue what I've found up til now so maybe someone else can pick this up or I'll get my computer fixed and can make a contribution.
It looks like I was a little mistaken about some things. Turns out you open the PR against upstream and mention your branch as the head. Using the example from above where I have a fork at joneshf/spr
and wanted to make a PR off of a some-branch-name
branch, it seems like it should look something like:
octocrab::instance()
.pulls(
"getcord", // Upstream organization
"spr", // Upstream repo
)
.create(
"…",
"joneshf:some-branch-name", // Origin repo and origin branch name
"master", // Upstream trunk branch
)
I don't think that's a big deal, just not really how I expected the GitHub API to work for PRs.
So it seems like the API calls that should be against origin would be just the one to create a branch, but everything else would be API calls against upstream. I might be missing some edge cases, but it definitely seems like most everything else you'd want to do is against the upstream (creating a PR, finding collaborators/teams, listing PRs, landing PRs, etc.).
As far as the config values, I was planning to add both a githubUpstreamRemoteName
and githubUpstreamRepository
to parallel the current githubRemoteName
and githubRepository
, respectively. Maybe the four names could be rethought to show the symmetry a bit better, but I leave it up to you to make the final call on that.
I expect there's probably some other stuff I'm missing, but might have to iterate on things for a bit to get where it's supposed to be. In any case, hopefully my computer sorts itself out soon.
Something that's worth discussing (because it might change the decision about whether to do this or not) is what to do about stacking PRs. Correct me if I'm wrong, but when working with only an origin repo, the way it works is that it creates a temporary branch as the base that is effectively the local parent commit (or all the remote parent commits squashed into one). While that's a pretty ingenious design, I'm not sure if it will work for a fork.
For a fork, the base branch has to exist in the upstream repo. Near as I can tell, that's going to be fairly rare since people are not likely to have write access to the upstream repo. Another idea would be to base the stacked PR on the first opened one, but that doesn't seem like it will work for a related reason.
Let's say I open a PR to upstream: getcord:master <- joneshf:first-branch
. Now I want to stack another PR on top of this: joneshf:first-branch <- joneshf:second-branch
. Well, the first PR is opened in getcord/spr
, but the second PR is opened in joneshf/spr
. In order to get someone in upstream to be aware of the stacked PRs, you have to tell them explicitly that there's a stack in your fork and whatnot. I mean it's possible, but it feels a bit obtuse.
All this to say, unless there's an equally ingenious idea about how to stack with forks, I think the only thing that spr
would be able to provide for forks is a good experience for the bottom of the stack. I personally would appreciate being able to use spr
from a fork. But I can respect if the fact that GitHub doesn't support stacked PRs well means that maybe spr
stays relegated to only working with an origin repo.
FWIW, the other spr
has determined it's a limitation in Github: ejoffe/spr#204