Merge lp:~lifeless/lptools/lp-project into lp:~dobey/lptools/trunk

Proposed by Robert Collins
Status: Merged
Merge reported by: dobey
Merged at revision: not available
Proposed branch: lp:~lifeless/lptools/lp-project
Merge into: lp:~dobey/lptools/trunk
Diff against target: 380 lines (+251/-69)
5 files modified
MANUAL.txt (+12/-0)
bin/lp-milestones (+8/-67)
bin/lp-project (+119/-0)
lptools/command.py (+101/-0)
lptools/config.py (+11/-2)
To merge this branch: bzr merge lp:~lifeless/lptools/lp-project
Reviewer Review Type Date Requested Status
Jelmer Vernooij (community) code Needs Fixing
dobey Pending
Review via email: mp+21124@code.launchpad.net

Description of the change

If its not obvious, call me names.

To post a comment you must log in.
Revision history for this message
Robert Collins (lifeless) wrote :

Ok, so now it needs an explanation. I've refactored the minimal command support stuff to permit it to be reused via convention in other front-end scripts.

lp:~lifeless/lptools/lp-project updated
13. By Robert Collins

Refactor CLI support to permit multiple front ends.

14. By Robert Collins

Cleanups.

15. By Robert Collins

Finish making the new command module work generically.

16. By Robert Collins

Bah, missed imports when migrating.

17. By Robert Collins

Add lp-project CLI script, which can create a project in launchpad.

Revision history for this message
Robert Collins (lifeless) wrote :

Final tweaks done - lp-project now exists, and 'lp-project create foo' will create a foo project, management team, mailing list and trunk branch in a fairly sensible layout.

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

This seems reasonable overall. It will have to be updated to not use edge, which has been deprecated.

review: Needs Fixing (code)
Revision history for this message
Robert Collins (lifeless) wrote :

I won't be able to do this for some time; care to tweak-as-landing ?

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

On 26/08/11 01:28, Robert Collins wrote:
> I won't be able to do this for some time; care to tweak-as-landing ?
Sure, happy to.

Cheers,

Jelmer

Revision history for this message
Jelmer Vernooij (jelmer) wrote :

This is now merged into lp:lptools; it won't show up here though, as this branch was originally proposed against Dobey's lptools trunk rather than the team one.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== added file 'MANUAL.txt'
2--- MANUAL.txt 1970-01-01 00:00:00 +0000
3+++ MANUAL.txt 2010-03-11 11:42:24 +0000
4@@ -0,0 +1,12 @@
5+=======
6+LPTools
7+=======
8+
9+Environment Variables
10+---------------------
11+
12+When running lptools, the variable LAUNCHPAD_API can be set to cause a specific
13+Launchpad service to be connected to. Current values are:
14+
15+* edge
16+* staging
17
18=== modified file 'bin/lp-milestones'
19--- bin/lp-milestones 2010-02-20 06:48:17 +0000
20+++ bin/lp-milestones 2010-03-11 11:42:24 +0000
21@@ -16,42 +16,19 @@
22 # You should have received a copy of the GNU General Public License along
23 # with this program. If not, see <http://www.gnu.org/licenses/>.
24
25-from __future__ import with_statement
26+"""lp-milestones -- An lptools command to work with milestones in launchpad.
27+https://launchpad.net/lptools/
28+
29+lp-milestones help commands -- list commands
30+"""
31+
32 import time
33-import optparse
34-import os
35-import sys
36
37 # Might want to make errors import lazy.
38-from bzrlib import commands, errors, ui, version_info as bzr_version_info
39+from bzrlib import errors
40 from launchpadlib.errors import HTTPError
41
42-from lptools import config
43-
44-def list_commands(command_names):
45- mod = sys.modules[__name__]
46- command_names.update(commands._scan_module_for_commands(mod))
47- return command_names
48-
49-
50-def get_command(cmd_or_None, cmd_name):
51- if cmd_name is None:
52- return cmd_help()
53- try:
54- return globals()['cmd_' + cmd_name]()
55- except KeyError:
56- return cmd_or_None
57-
58-
59-class LaunchpadCommand(commands.Command):
60- """Base class for commands working with launchpad."""
61-
62- def run_argv_aliases(self, argv, alias_argv=None):
63- # This might not be unique-enough for a cachedir; can do
64- # lp-milestones/cmdname if needed.
65- self.launchpad = config.get_launchpad('lp-milestones')
66- return commands.Command.run_argv_aliases(self, argv, alias_argv)
67-
68+from lptools.command import *
69
70 class cmd_create(LaunchpadCommand):
71 """Create a milestone.
72@@ -108,25 +85,6 @@
73 raise
74
75
76-class cmd_help(commands.Command):
77- """Show help on a command or other topic."""
78-
79- # Can't use the stock bzrlib help, because the help indices aren't quite
80- # generic enough.
81- takes_args = ['topic?']
82- def run(self, topic=None):
83- if topic is None:
84- self.outf.write(
85-"""lp-milestones -- An lptools command to work with milestones in launchpad.
86-https://launchpad.net/lptools/
87-
88-lp-milestones help commands -- list commands
89-""")
90- else:
91- import bzrlib.help
92- bzrlib.help.help(topic)
93-
94-
95 class cmd_release(LaunchpadCommand):
96 """Create a release from a milestone.
97
98@@ -168,22 +126,5 @@
99 m.lp_save()
100
101
102-def do_run_bzr(argv):
103- if bzr_version_info > (2, 2, 0):
104- # in bzr 2.2 we can disable bzr plugins so bzr commands don't show
105- # up.
106- return commands.run_bzr(argv, lambda:None, lambda:None)
107- else:
108- return commands.run_bzr(argv)
109-
110-
111-def main():
112- commands.Command.hooks.install_named_hook('list_commands', list_commands,
113- "list")
114- commands.Command.hooks.install_named_hook('get_command', get_command,
115- "get")
116- ui.ui_factory = ui.make_ui_for_terminal(sys.stdin, sys.stdout, sys.stderr)
117- sys.exit(commands.exception_to_return_code(do_run_bzr, sys.argv[1:]))
118-
119 if __name__ == "__main__":
120 main()
121
122=== added file 'bin/lp-project'
123--- bin/lp-project 1970-01-01 00:00:00 +0000
124+++ bin/lp-project 2010-03-11 11:42:24 +0000
125@@ -0,0 +1,119 @@
126+#!/usr/bin/python
127+#
128+# Author: Robert Collins <robert.collins@canonical.com>
129+#
130+# Copyright 2010 Canonical Ltd.
131+#
132+# This program is free software: you can redistribute it and/or modify it
133+# under the terms of the GNU General Public License version 3, as published
134+# by the Free Software Foundation.
135+#
136+# This program is distributed in the hope that it will be useful, but
137+# WITHOUT ANY WARRANTY; without even the implied warranties of
138+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
139+# PURPOSE. See the GNU General Public License for more details.
140+#
141+# You should have received a copy of the GNU General Public License along
142+# with this program. If not, see <http://www.gnu.org/licenses/>.
143+
144+"""lp-project -- An lptools command to work with projects in Launchpad.
145+https://launchpad.net/lptools/
146+
147+lp-project help commands -- list commands
148+"""
149+
150+import time
151+import os
152+import sys
153+
154+# Might want to make errors import lazy.
155+from bzrlib import bzrdir, directory_service, errors, transport
156+from launchpadlib.errors import HTTPError
157+
158+from lptools.command import *
159+
160+class cmd_create(LaunchpadCommand):
161+ """Create a project.
162+
163+ This creates two teams - a management/committer team owner by you and
164+ a -dev mailing list owned by the mgmt team. It then creates the project,
165+ makes it owned by the committer team, creates a new empty bzr branch for
166+ trunk and then fires up a web browser pointing at the project for you to
167+ fine tune.
168+
169+ After running this command you need to:
170+ - set what LP features you are using
171+ (https://bugs.edge.launchpad.net/launchpad/+bug/537269)
172+ - describe your project (title, summary, description)
173+ - upload your code to lp:PROJECT
174+ - turn on the mailing list by hand
175+ (https://bugs.edge.launchpad.net/launchpad/+bug/537258)
176+
177+ lp-project create projectname
178+ """
179+
180+ takes_args = ['project']
181+
182+ def run(self, project):
183+ self.outf.write('creating project %s\n' % project)
184+ #load the lp plugin - we needs it, but don't want its commands shown.
185+ from bzrlib.plugins import launchpad
186+ project_d = {'project':project}
187+ mgmt = self.launchpad.people.newTeam(
188+ display_name='%s committers' % project, name=project,
189+ subscription_policy='Moderated Team', team_description="This is the"
190+ " %(project)s project maintainers and committers team. Membership "
191+ "in this team grants commit access to the %(project)s trunk and "
192+ "release branches, and owner access to the project. To become a "
193+ "member of this team, please contact the project via the "
194+ "%(project)s-dev mailing list." % {'project':project})
195+ dev = self.launchpad.people.newTeam(
196+ display_name='%s mailing list' % project, name='%s-dev' % project,
197+ subscription_policy='Open Team', team_description="This is the"
198+ " %(project)s (https://launchpad.net/%(project)s) development "
199+ "discussion mailing list. To subscribe to the list join this team "
200+ "(it does not receive bug mail or other such dross)." % project_d)
201+ dev.team_owner = mgmt
202+ dev.lp_save()
203+ proj = self.launchpad.projects.new_project(
204+ display_name=project,
205+ name=project,
206+ registrant=mgmt,
207+ title="Put what you want to show in browser window titles for %s "
208+ "here" % project,
209+ description="""Put a long description of the %(project)s project here.
210+
211+A mailing list for discussion, usage and development is at https://launchpad.net/~%(project)s-dev - all are welcome to join. Some folk hang out on #%(project)s on irc.freenode.net.
212+""" % project_d,
213+ home_page_url="https://launchpad.net/%s" % project,
214+ summary="Put a pithy summary of %s here." % project,
215+ )
216+ proj.bug_reporting_guidelines = """Enough data to reproduce the behaviour if possible.
217+
218+If that is not possible, just describe as well as you can what is happening and we will talk through the issue with you.
219+"""
220+ proj.owner = mgmt
221+ proj.lp_save()
222+ branch_path = '~%(project)s/%(project)s/trunk' % project_d
223+ lp_host = os.environ.get('LAUNCHPAD_API', '')
224+ if lp_host:
225+ lp_host = '//%s/' % lp_host
226+ branch = bzrdir.BzrDir.create_branch_convenience(
227+ 'lp:%s%s' % (lp_host, branch_path), force_new_tree=False)
228+ series = proj.getSeries(name='trunk')
229+ series.branch_link = self.launchpad.load(branch_path)
230+ series.lp_save()
231+ self.outf.write("""
232+Project created at %s (sorry about the url. (https://bugs.edge.launchpad.net/launchpadlib/+bug/316694)).
233+You now need to:
234+ - set what LP features you are using
235+ (https://bugs.edge.launchpad.net/launchpad/+bug/537269)
236+ - describe your project (title, summary, description)
237+ - upload your code to lp:PROJECT
238+ - turn on the mailing list by hand
239+ (https://bugs.edge.launchpad.net/launchpad/+bug/537258)
240+""" % proj.self_link)
241+
242+
243+if __name__ == "__main__":
244+ main()
245
246=== added file 'lptools/command.py'
247--- lptools/command.py 1970-01-01 00:00:00 +0000
248+++ lptools/command.py 2010-03-11 11:42:24 +0000
249@@ -0,0 +1,101 @@
250+# Author: Robert Collins <robert.collins@canonical.com>
251+#
252+# Copyright 2010 Canonical Ltd.
253+#
254+# This program is free software: you can redistribute it and/or modify it
255+# under the terms of the GNU General Public License version 3, as published
256+# by the Free Software Foundation.
257+#
258+# This program is distributed in the hope that it will be useful, but
259+# WITHOUT ANY WARRANTY; without even the implied warranties of
260+# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR
261+# PURPOSE. See the GNU General Public License for more details.
262+#
263+# You should have received a copy of the GNU General Public License along
264+# with this program. If not, see <http://www.gnu.org/licenses/>.
265+
266+"""Command abstraction for the CLI parts of lptools.
267+
268+To use:
269+
270+* in your front end script define a docstring - this is used for global help.
271+
272+* from this module import *
273+
274+* derive commands from LaunchpadCommand and call them cmd_NAME.
275+
276+* At the bottom of your script, do::
277+
278+ if __name__ == '__main__':
279+ main()
280+"""
281+
282+__all__ = [
283+ 'LaunchpadCommand',
284+ 'main',
285+ ]
286+
287+import os
288+import sys
289+
290+from bzrlib import commands, ui, version_info as bzr_version_info
291+
292+from lptools import config
293+
294+def list_commands(command_names):
295+ mod = sys.modules['__main__']
296+ command_names.update(commands._scan_module_for_commands(mod))
297+ return command_names
298+
299+
300+def get_command(cmd_or_None, cmd_name):
301+ if cmd_name is None:
302+ return cmd_help()
303+ elif cmd_name == 'help':
304+ return cmd_help()
305+ klass = getattr(sys.modules['__main__'], 'cmd_' + cmd_name, None)
306+ if klass is not None:
307+ return klass()
308+ return cmd_or_None
309+
310+
311+class LaunchpadCommand(commands.Command):
312+ """Base class for commands working with launchpad."""
313+
314+ def run_argv_aliases(self, argv, alias_argv=None):
315+ # This might not be unique-enough for a cachedir; can do
316+ # $frontend/cmdname if needed.
317+ self.launchpad = config.get_launchpad(os.path.basename(sys.argv[0]))
318+ return commands.Command.run_argv_aliases(self, argv, alias_argv)
319+
320+
321+class cmd_help(commands.Command):
322+ """Show help on a command or other topic."""
323+
324+ # Can't use the stock bzrlib help, because the help indices aren't quite
325+ # generic enough.
326+ takes_args = ['topic?']
327+ def run(self, topic=None):
328+ if topic is None:
329+ self.outf.write(sys.modules['__main__'].__doc__)
330+ else:
331+ import bzrlib.help
332+ bzrlib.help.help(topic)
333+
334+
335+def do_run_bzr(argv):
336+ if bzr_version_info > (2, 2, 0):
337+ # in bzr 2.2 we can disable bzr plugins so bzr commands don't show
338+ # up.
339+ return commands.run_bzr(argv, lambda:None, lambda:None)
340+ else:
341+ return commands.run_bzr(argv)
342+
343+
344+def main():
345+ commands.Command.hooks.install_named_hook('list_commands', list_commands,
346+ "list")
347+ commands.Command.hooks.install_named_hook('get_command', get_command,
348+ "get")
349+ ui.ui_factory = ui.make_ui_for_terminal(sys.stdin, sys.stdout, sys.stderr)
350+ sys.exit(commands.exception_to_return_code(do_run_bzr, sys.argv[1:]))
351
352=== modified file 'lptools/config.py'
353--- lptools/config.py 2010-02-20 04:46:06 +0000
354+++ lptools/config.py 2010-03-11 11:42:24 +0000
355@@ -55,10 +55,10 @@
356 creds = Credentials()
357 with file(credspath) as f:
358 creds.load(f)
359- return launchpad.Launchpad(creds, EDGE_SERVICE_ROOT, cachedir)
360+ return launchpad.Launchpad(creds, _service_root(), cachedir)
361 else:
362 result = launchpad.Launchpad.get_token_and_login('lptools',
363- EDGE_SERVICE_ROOT, cachedir)
364+ _service_root(), cachedir)
365 with file(credspath, "w") as f:
366 result.credentials.save(f)
367 return result
368@@ -81,3 +81,12 @@
369 cachedir = lptools_cachedir()
370 ensure_dir(cachedir)
371 return os.path.join(lptools_cachedir(), 'credentials')
372+
373+
374+def _service_root():
375+ """Get the service root to connect to.
376+
377+ By default this is EDGE_SERVICE_ROOT. If LAUNCHPAD_API is set in the
378+ environment, that value is used instead.
379+ """
380+ return os.environ.get('LAUNCHPAD_API', EDGE_SERVICE_ROOT)

Subscribers

People subscribed via source and target branches

to all changes: