-
Notifications
You must be signed in to change notification settings - Fork 89
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add GitBucket support (refs #142) #144
Conversation
hi @kounoike I'm starting to review your code, and I'd appreciate if you could split it in a four commits, one per file. Because it's likely I won't merge your PR as is, but rather gradually (the fixes first, and the gitbucket after), so I'd like to be able to preserve attribution to you for your changes 😉 |
1bf4c23
to
cebf92d
Compare
@guyzmo Thanks to review! OK, I will split my commit. But, I'm not accustomed to such non-standard Git operations. I split to four commit locally. How to push it for GitHub? |
Thank you! You should |
@guyzmo OK. I pushed it! |
git_repo/services/service.py
Outdated
@@ -244,7 +244,10 @@ def format_path(self, repository, namespace=None, rw=False): | |||
if not rw and '/' in repo: | |||
return '{}/{}'.format(self.url_ro, repo) | |||
elif rw and '/' in repo: | |||
return '{}:{}'.format(self.url_rw, repo) | |||
if self.url_rw.startswith('ssh://'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
in what context do you need ssh://
URIs? As far as I can tell, it's not supported by neither Git or SSH directly (only by xdg-
tools or browsers.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
GitBucket's ssh url is: ssh://git@server:29418/root/repo.git
GitBucket doesn't use system sshd. It uses embedded sshd. So, it can't listen on 22 port.
By Git manual, "An alternative scp-like syntax" doesn't take ssh port. So it is required for GitBucket with ssh repository access. and ssh://
protocol is supported officially.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Interesting, that I did not know.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
could you update the commits related to that change the title of the commits to 'Adds missing ssh:// URL support' and in the body the details above? It's not only for GitBucket support, it's actually an important fix 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I fixed it now. push -f
again?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yup 👍
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
pushed!
git_repo/repo.py
Outdated
*_, user, name = url.split('/') | ||
self.set_repo_slug('/'.join([user, name])) | ||
return | ||
elif url.startswith('ssh://'): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of repeating the above code body below, you can simply write:
if url.startswith('https') or url.startswith('http') or url.startswith('ssh'):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I will fix it, but I think it is more better:
if url.startswith('https://') or url.startswith('http://') or url.startswith('ssh://'):
because, "An alternative scp-like syntax" can use any username such as:
http@server:owner/repo.git
https@server:owner/repo.git
ssh@server:owner/repo.git
I know these format can be used by Gogs. Gogs can configure ssh username. (Of course it is rare case)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Gogs can configure ssh username. (Of course it is rare case)
hmm... it means startswith('git@')
doesn't match for Gogs...
In my Gogs instance running on Raspberry Pi, ssh URL is: pi@raspberrypi.local:test/test.git
But it is not GitBucket related fix. Which is better action?
Should I create new Issue/PR? or fix it in this PR?
It should be rewrite as:
for url in remote.urls:
if url.endswith('.git'):
url = url[:-4]
if url.find('://') > -1:
*_, user, name = url.split('/')
self.set_repo_slug('/'.join([user, name]))
return
elif url.find('@') > -1:
_, repo_slug = url.split(':')
self.set_repo_slug(repo_slug)
return
but it is not tested.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
well, I'm ok if you take all the SSH format fixes as another PR.
I was anyway planning to merge them first before merging your gitbucket PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if you do another PR, make a branch for each PR and don't forget to rebase the branch for this PR on top of the other one! ☺
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks, I do it.
But it contains 'Change local branch name to remote repo name.' commit.
I think it is not related change for ssh:// URL things.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's ok, it's a minor bug that also needs to get fixed 😉
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I create new PR #148 for ssh://
and user@server:pathto/repo.git
URL fixes. and I will remove these changes.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nah, you can keep this PR on top of the other PR it's ok, I'm merging it ASAP
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
just add the third commit you forgot 😉
git_repo/repo.py
Outdated
*_, user, name = url.split('/') | ||
self.set_repo_slug('/'.join([user, name])) | ||
return | ||
elif url.startswith('ssh://'): | ||
*_, user, name = url.split('/') | ||
self.set_repo_slug('/'.join([user, name])) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
if we were keeping that body, the return
statement is missing here, to break from the for
loop. (technically, it's more a break
than a return
, but in this case they're the same).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the commit " Change slug detection code. (for GitBucket compatibility)" should also change, it's related to the other ssh://
change, i.e.: it's a bugfix not just a GitBucket thing.
git_repo/services/ext/gitbucket.py
Outdated
@classmethod | ||
def get_auth_token(cls, login, password, prompt=None): | ||
print("Please edit _YOUR_ACCESS_TOKEN_ to actual token in ~/.gitconfig or ~/.git/config after.") | ||
print("And add ssh-url = ssh://git@{}:_YOUR_SSH_PORT_".format(cls.fqdn)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
instead of hacking your way like that, you can actually do:
print("Please open the following URL: https://yourgitbucket/where/are/in/settings/auth/tokens")
print("Generate a new token, and paste it at the following prompt.")
return prompt('token> ')
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
the prompt parameter is actually the loop_input
callback given from git-repo's CLI interface.
git_repo/services/ext/gitbucket.py
Outdated
super(GitbucketService, self).__init__(*args, **kwarg) | ||
|
||
def connect(self): | ||
self.gh = github3.GitHubEnterprise(self.build_url(self)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe this could be done in GithubService
itself: if the URL is github.com
it's github3.GitHub
, otherwise it's GithubEnterprise
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I want to replace self.gh
object from github3.GitHub
to github3.GithHubEnterprise
with GitBucket's API endpoint URL.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, but that's going to be an issue. The self.gh
instance shall be created in the constructor as first line even before the call the the constructor.
The reason for that is the tests, where it pulls the session
instance out of the self.gh
instance. If you change the self.gh
instance at self.connect()
time, there's a high probability that the tests will be testing another session instance than the one you're actually using in your methods.
So, we could patch GithubService.__init__()
so that:
GITHUB_FQDN='github.com'
@register_target('hub', 'github')
class GithubService(RepositoryService):
fqdn = GITHUB_FQDN
def __init__(self, *args, **kwarg):
if self.fqdn == GITHUB_FQDN:
self.gh = github3.GitHub()
else:
self.gh = github3.GitHubEnterprise(RepositoryService.build_url(self))
super(GithubService, self).__init__(*args, **kwarg)
```
and as a side effect, there's a chance that actually it enables `GithubService` to work with self hosted github instances… out of the box 🙌
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I try it. but it doesn't load fqdn/port from configuration on this phase. Because, load_configuration is called by RepositoryService.__init__
. And RepositoryService.__init__
also calls self.connect
, so self.gh must be initialized before init called.
@guyzmo do you have any idea?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, I'll make a ticket to github3.py for this issue, so he splits the init in several steps. (by having a default URL to an empty invalid value, and a set_url()
method)
Currently, here's the code it is doing at startup time.
So we keep my suggestion above, but the connect()
method shall change:
def connect(self):
self.gh._session.base_url = url.rstrip('/') + '/api/v3'
self.gh._session.verify = self.session_certificate or not self.session_insecure
super(GitbucketService, self).connect()
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
...?
I talk about timing of loading settings from .gitconfig
.
- on
GitBucketService.__init__
callsGithubService.__init__
- on
GithubService.__init__
, assignself.gh
toGitHubEnterprise
withbuild_url
- on
GithubService.__init__
, callsRepositoryService.__init__
- on
RepositoryService.__init__
callsload_configuration
.gitconfig
's fqdn/port settings load at 4. but build_url
called at 2.
and even if rewrite __init__
in github.py
as:
def __init__(self, *args, **kwarg):
super(GithubService, self).__init__(*args, **kwarg)```
if self.fqdn == GITHUB_COM_FQDN:
self.gh = github3.GitHub()
else:
self.gh = github3.GitHubEnterprise(RepositoryService.build_url(self))
it get error because RepositoryService.__init__
calls self.connect
. it uses self.gh
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The order is:
- init phase:
- instanciate session (and stuff that go with it)
- load configuration
- connect phase:
- if need be, overload the github reference (but preserve the session)
- do the connect stuff
basically here's the fixed gist:
GITHUB_FQDN='github.com'
@register_target('hub', 'github')
class GithubService(RepositoryService):
fqdn = GITHUB_FQDN
def __init__(self, *args, **kwarg):
self.gh = github3.GitHub()
super(GithubService, self).__init__(*args, **kwarg)
def connect(self):
if self.fqdn != GITHUB_FQDN:
# upgrade self.gh from a GitHub object to a GitHubEnterprise object
gh = github3.GitHubEnterprise(RepositoryService.build_url(self))
self.gh._session.base_url = gh._session.base_url
self.gh = gh
# propagate ssl certificate parameter
self.gh._session.verify = self.session_certificate or not self.session_insecure
try:
self.gh.login(token=self._privatekey)
self.username = self.gh.user().login
except github3.models.GitHubError as err:
if 401 == err.code:
if not self._privatekey:
raise ConnectionError('Could not connect to Github. '
'Please configure .gitconfig '
'with your github private key.') from err
else:
raise ConnectionError('Could not connect to Github. '
'Check your configuration and try again.') from err
git_repo/services/ext/gitbucket.py
Outdated
def format_path(self, repository, namespace=None, rw=False): | ||
path = super(GitbucketService, self).format_path(repository, namespace, rw) | ||
if not path.endswith(".git"): | ||
path = "{}.git".format(path) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the .git
ending of a path really mandatory with GitBucket
? I find that quite surprising.
For the note, Github support both with and without the extension (i.e. https://github.com/guyzmo/git-repo.git or https://github.com/guyzmo/git-repo)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I know it.
In GitBucket,
for ssh access, .git
is required.
for http(s) access, GitBucket's formal http(s) URL format is http://server:port/git/owner/repo.git
.
But it also can access with:
http://server:port/git/owner/repo
http://server:port/owner/repo.git
But it can't access by http://server:port/owner/repo
. Then it always add .git
.
Recently, I found problem with git-2.12. I wrote it in gitbucket/gitbucket#1552.
In GitBucket-4.12, http://server:port/owner/repo.git
returns redirect to http://server:port/git/owner/repo.git
. git-2.12 doesn't allow redirect url.
so I will rewrite format_path
such as:
- never call
super(...).format_path
- returns
ssh://user@server:port/owner/repo.git
for rw=True - returns
http://server:port/git/owner/repo.git
for rw=False
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
ok, makes sense
@register_target('bucket', 'gitbucket') | ||
class GitbucketService(GithubService): | ||
fqdn = "localhost" | ||
port = 8080 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is there a public instance we can default to, for testing and tweaking?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There is demo site at https://gitbucket.herokuapp.com/
But I don't know who maintains it, who pays money for heroku's charge. So I can't decide it to default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And it's not opened for accounts. It'd be nice to find an almost open instance, like gogs do, to default to it for tests and all.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
try.gogs.io is down now...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
it's nice that we recorded the tests before it went down 😁
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
can you implement also the tests?
you can basically copy/paste the github ones, and guard all the tests that are not implement with:
with pytest.raises(NotImplemented):
...
so they're already there for when they will be done.
Could you also add script(s) that can automatically instanciate a gitbucket instance, like for gogs?
can you rebase this branch on top of the devel branch of |
ok, so I've rebased this branch on devel in the branch Let's consider the following two remotes:
if it's not like that, adapt accordingly to what you chose # first make sure you're in this PR's branch
git checkout pr-gitbucket
# then make a backup of it
git checkout -b pr-gitbucket-backup
# remove the branch
git branch -D pr-gitbucket
# fetch the branch I've pushed
git fetch upstream requests/github/144
# check out that branch
git checkout upstream/requests/github/144
# store that branch locally as the new pr-gitbucket
git checkout -b pr-gitbucket
# and force push it to your github project
git push -f github pr-gitbucket
# and now this PR is rebased on the new main devel branch PS: you can use git-repo to add the git hub add github kounoike/git-repo
git hub add -a upstream guyzmo/git-repo 😉 |
Once the above is done, I'll need you to:
and BTW, thank you for your care so far 🙌 |
if self.fqdn != GITHUB_COM_FQDN: | ||
# upgrade self.gh from a GitHub object to a GitHubEnterprise object | ||
gh = github3.GitHubEnterprise(RepositoryService.build_url(self)) | ||
self.gh._session.base_url = gh._session.base_url |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this is wrong, it should be the other way around:
gh._session.base_url = self.gh._session.base_url
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK I fixed it.
- self.gh must change to new one(GitHubEnterprise)
- self.gh._session must keeps old one(created by init)
- self.gh._session.base_url must change to new URL
gh = github3.GitHubEnterprise(RepositoryService.build_url(self))
self.gh._session.base_url = gh._session.base_url
gh._session = self.gh._session
self.gh = gh
First anniversary release 🎂 This release marks the first anniversary and 10th release of git-repo 🎉 Now git-repo supports 6 git services: github, gitlab, bitbucket, gogs, gitea and gitbucket It supports the following commands: clone, fork, create, delete, add, open, ls, request, gist And it's becoming relatively stable (keep sending bug reports 🙏) ♥ Contributors Thanks to @kounoike for the gitbucket support 🙌 Now there are three contributors promoted to collaborators: * @kounoike, @pyhedgehog and @Crazybus 🚧 Features * When add has no parameters, add default remote #100 #141 * When add has 'upstream' parameter, add the upstream remote #99 #141 * Use default branch instead of hardcoded 'master' #91 * Refactor and complete bitbucket support #43 #11 #80 #14 #89 #90 #79 * Loosen versions of dependencies #133 * Report if the service is already setup #136 * Adds GitBucket support #142 #144 * Adds support for ssh:// URL #148 🚒 Bugfixes * fix various crashes #152 * fix gitlab clone crash #129 * fix request create command #147 #127 * fix request fetch command #138 #131 * fix wizard crash #149 * fix mishandling of renamed gitlab project urls #137 📝 Documentation * documentation #145 Signed-off-by: Guyzmo <guyzmo+github+pub@m0g.net>
GitBucket is Git platform with high-API compatibility to GitHub (for client, GitBucket looks like as GitHub Enterprise).
This PR add GitBucket support with some actions.
There are few changes to git-repo side.
gitbucket.py now supports
these action doesn't supported now.
git repo config