Skip to content

Commit 0b4a9fc

Browse files
committed
👍 Merge branch 'devel' ; Version bump to 1.7.0!
* Improved CLI API ; * Made repo slug optional for commands that don't need it ; * Added auto configuration command. * fixes issue #9: Make requests for merges not needing repo slug * fixes issue #17: Refactoring of main function * fixes issue #21: Add auto-configuration command Signed-off-by: Guyzmo <[email protected]>
2 parents b4f3727 + 44e13ac commit 0b4a9fc

22 files changed

+1979
-276
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@ README.rst
1313
*.egg
1414
.cache/
1515
.coverage
16+
contrib
17+
docs
18+
.gitignore

README.md

Lines changed: 36 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,13 @@
55
* https://gitlab.com/guyzmo/git-repo
66
* https://bitbucket.org/guyzmo/git-repo
77
* Issues: https://github.com/guyzmo/git-repo/issues
8-
* [![Show Travis Build Status](https://travis-ci.org/guyzmo/git-repo.svg)](https://travis-ci.org/guyzmo/git-repo)
8+
* [![Issues in Ready](https://badge.waffle.io/guyzmo/git-repo.png?label=ready&title=Ready)](https://waffle.io/guyzmo/git-repo) [![Issues in Progress](https://badge.waffle.io/guyzmo/git-repo.png?label=in%20progress&title=Progress)](https://waffle.io/guyzmo/git-repo) [![Show Travis Build Status](https://travis-ci.org/guyzmo/git-repo.svg)](https://travis-ci.org/guyzmo/git-repo)
99
* [![Pypi Version](https://img.shields.io/pypi/v/git-repo.svg) ![Pypi Downloads](https://img.shields.io/pypi/dm/git-repo.svg)](https://pypi.python.org/pypi/git-repo)
1010

1111
### Usage
1212

13+
### main commands
14+
1315
Control your remote git hosting services from the `git` commandline. The usage is
1416
very simple. To clone a new project, out of github, just issue:
1517

@@ -48,6 +50,13 @@ and of course, you can delete it using:
4850

4951
% git bb delete guyzmo/git-repo
5052

53+
Also, you can open the repository's page, using the `open` command:
54+
55+
% git lab open guyzmo/git-repo
56+
Successfully fetched branch `2` of `guyzmo/git-repo` into `request-2`!
57+
58+
### Requests for merges *(aka Pull Requests aka Merge Requests)*
59+
5160
Once you're all set with your repository, you can check requests to merge
5261
(aka Pull Requests on github) using the `request` command:
5362

@@ -60,10 +69,11 @@ And fetch it locally to check and/or amend it before merging:
6069

6170
% git hub request guyzmo/git-repo fetch 2
6271

63-
Finally, you can open the repository's page, using the `open` command:
72+
Or you can create a pull-request by doing a:
6473

65-
% git lab open guyzmo/git-repo
66-
Successfully fetched branch `2` of `guyzmo/git-repo` into `request-2`!
74+
% git hub request create guyzmo/git-repo myfeature master 'My neat feature' -m 'So much to say about that feature…'
75+
76+
### Gists or snippets
6777

6878
Finally, another extra feature you can play with is the gist handling:
6979

@@ -119,8 +129,17 @@ or by getting the sources and running:
119129

120130
### Configuration
121131

122-
To configure `git-repo` you need to tweak your `~/.gitconfig`. For each service
123-
you've got an account on, you have to make a section in the gitconfig:
132+
To configure `git-repo` you simply have to call the following command:
133+
134+
% git repo config
135+
136+
and a wizard will run you through getting the authentication token for the
137+
service, add the command alias or the name of the remote. Though, configuring
138+
custom services is still not handled by the wizard…
139+
140+
But if you prefer manual configuration you'll have to tweak your
141+
`~/.gitconfig`. For each service you've got an account on, you have to make a
142+
section in the gitconfig:
124143

125144
[gitrepo "gitlab"]
126145
token = YourVerySecretKey
@@ -218,21 +237,21 @@ To use your own credentials, you can setup the following environment variables:
218237
* [x] refactor the code into multiple modules
219238
* [x] add regression tests (and actually find a smart way to implement them…)
220239
* [x] add travis build
240+
* [x] show a nice progress bar, while it's fetching (cf [#15](https://github.com/guyzmo/git-repo/issues/15))
221241
* [ ] add support for handling gists
222242
* [x] github support
223-
* [ ] gitlab support
224-
* [ ] bitbucket support
243+
* [ ] gitlab support (cf [#12](https://github.com/guyzmo/git-repo/issues/12))
244+
* [ ] bitbucket support (cf [#13](https://github.com/guyzmo/git-repo/issues/13))
225245
* [ ] add support for handling pull requests
226-
* [x] list them
227-
* [x] fetch them as local branches
228246
* [x] github support
229-
* [ ] gitlab support
230-
* [ ] bitbucket support
231-
* [ ] add OAuth support for bitbucket
232-
* [ ] show a nice progress bar, while it's fetching
233-
* partly implemented: the issue looks like that gitpython expects output from git
234-
on stderr, whereas it's outputing on stdout.
235-
* [ ] do what's needed to make a nice documentation (if possible in markdown !@#$)
247+
* [ ] gitlab support (cf [#10](https://github.com/guyzmo/git-repo/issues/10))
248+
* [ ] bitbucket support (cf [#11](https://github.com/guyzmo/git-repo/issues/11))
249+
* [ ] add OAuth support for bitbucket (cf [#14](https://github.com/guyzmo/git-repo/issues/14))
250+
* [ ] add support for managing SSH keys (cf [#22](https://github.com/guyzmo/git-repo/issues/15))
251+
* [ ] add support for issues?
252+
* [ ] add support for gogs (cf [#18](https://github.com/guyzmo/git-repo/issues/18))
253+
* [ ] add support for gerrit (cf [#19](https://github.com/guyzmo/git-repo/issues/19))
254+
* [ ] do what's needed to make a nice documentation — if possible in markdown !@#$
236255
* for more features, write an issue or, even better, a PR!
237256

238257
### License

VERSION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
1.7.0

buildout.cfg

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -7,29 +7,29 @@ develop = .
77
eggs-directory = ${buildout:directory}/var/eggs
88
develop-eggs-directory = ${buildout:directory}/var/develop-eggs
99
parts-directory = ${buildout:directory}/var/parts
10-
develop-dir = ${buildout:directory}/var/clone/
11-
extensions=gp.vcsdevelop
12-
vcs-extend-develop=git+https://github.com/gitpython-developers/GitPython#egg=GitPython
10+
# develop-dir = ${buildout:directory}/var/clone/
11+
# extensions=gp.vcsdevelop
12+
# vcs-extend-develop=git+https://github.com/gitpython-developers/GitPython#egg=GitPython
1313

1414
[git_repo]
1515
recipe = zc.recipe.egg
1616
eggs =
17+
${git_repo-pip:eggs}
1718
git_repo
1819
interpreter = python3
1920

2021
[pytest]
2122
recipe = zc.recipe.egg
2223
arguments = ['--cov=git_repo', '--cov-report', 'term-missing', '--capture=sys', 'tests']+sys.argv[1:]
23-
eggs = pytest
24-
pytest-cov
25-
pytest-xdist
26-
pytest-sugar
27-
pytest-catchlog
28-
pytest-datadir-ng
29-
testfixtures
30-
mock
31-
betamax==0.5.1
32-
betamax-serializers
33-
git_repo
24+
eggs = ${pytest-pip:eggs}
3425
interpreter = python3
3526

27+
[git_repo-pip]
28+
recipe = collective.recipe.pip
29+
configs = ${buildout:directory}/requirements.txt
30+
31+
[pytest-pip]
32+
recipe = collective.recipe.pip
33+
configs = ${buildout:directory}/requirements-test.txt
34+
35+

git_repo/kwargparse.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
#!/usr/bin/env python
2+
3+
import logging
4+
log = logging.getLogger('git_repo.kwargparse')
5+
6+
class KeywordArgumentParser:
7+
'''
8+
Argument parser tailored for use with docopt:
9+
10+
Will parse all arguments returned by docopt, and will store them as instance
11+
attributes. Then it will launch actions based on the keyword argument list.
12+
13+
* Parameter arguments (starting with -- or within <>) will automagically be
14+
parsed, dashes will be converted to underscores and stored as attributes of
15+
the parser instance.
16+
* Though if a parameter is matching a method decorated with "store_parameter",
17+
it won't be automagically setup, but will use that method instead.
18+
19+
Then the keywords used as arguments of the program will be used to call an
20+
"action" method, which have been decorated with "register_action".
21+
22+
'''
23+
_action_dict = dict()
24+
_parameter_dict = dict()
25+
26+
def __init__(self, args):
27+
'''
28+
Stores the docopt args as class member
29+
'''
30+
self.args = args
31+
32+
def init(self):
33+
'''
34+
method to be defined for anything that needs to be done before launching
35+
the parser.
36+
'''
37+
pass
38+
39+
def run(self):
40+
'''
41+
This method iterates over the docopt's arguments and matches them against
42+
the parameters list. All leftover values are used to resolve the action to
43+
run, and it will run the action, or run the fallback() method if no action
44+
is found.
45+
'''
46+
self.init()
47+
48+
args = []
49+
missed = []
50+
51+
# go through setters
52+
for arg, value in self.args.items():
53+
if arg in self._parameter_dict:
54+
self._parameter_dict[arg](self, value)
55+
#log.debug('calling setter: {} → {}'.format(arg, value))
56+
elif arg.startswith('--') or arg.startswith('<'):
57+
arg_renamed = arg.lstrip('-<').rstrip('>').replace('-', '_')
58+
if not hasattr(self, arg_renamed):
59+
setattr(self, arg_renamed, value)
60+
#log.debug('auto-setting: self.{} → {}'.format(arg_renamed, value))
61+
else:
62+
#log.debug('keeping: {} → {}'.format(arg, value))
63+
if self.args[arg]:
64+
args.append(arg)
65+
66+
if frozenset(args) in self._action_dict:
67+
#log.debug('running action: {}'.format(self._action_dict[frozenset(args)]))
68+
return self._action_dict[frozenset(args)](self)
69+
else:
70+
return self.fallback()
71+
72+
def fallback(self):
73+
log.error('Unknown action.')
74+
log.error('Please consult help page (--help).')
75+
return 1
76+
77+
78+
79+
def store_parameter(parameter):
80+
'''
81+
Decorator for a parameter, use the full length parameter name as specified in the
82+
docopt configuration, like '--verbose'
83+
'''
84+
def decorator(fun):
85+
KeywordArgumentParser._parameter_dict[parameter] = fun
86+
return fun
87+
return decorator
88+
89+
def register_action(*args, **kwarg):
90+
'''
91+
Decorator for an action, the arguments order is not relevant, but it's best
92+
to use the same order as in the docopt for clarity.
93+
'''
94+
def decorator(fun):
95+
KeywordArgumentParser._action_dict[frozenset(args)] = fun
96+
return fun
97+
return decorator

0 commit comments

Comments
 (0)