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

Proposed by Robert Collins on 2010-03-11
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 on 2011-08-25
dobey 2010-03-11 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.
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 on 2010-03-11
13. By Robert Collins on 2010-03-11

Refactor CLI support to permit multiple front ends.

14. By Robert Collins on 2010-03-11

Cleanups.

15. By Robert Collins on 2010-03-11

Finish making the new command module work generically.

16. By Robert Collins on 2010-03-11

Bah, missed imports when migrating.

17. By Robert Collins on 2010-03-11

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

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.

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)
Robert Collins (lifeless) wrote :

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

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

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: