~matsubara/tarmac/test-staging

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
======================
Writing Tarmac Plugins
======================

What's the point in having a plugin system if you can't actually write plugins
easily?  Tarmac's plugins make it easy for you to bend Tarmac's functionality
to your will.  This document describes the process of writing the plugins.

Writing a Plugin
================

A plugin is merely a python class inheriting from
``tarmac.plugins.TarmacPlugin``.  It has a pre-determined API, but is very
trivial to connect.  For example, a basic HelloWorldPlugin would start like
this::

  from tarmac.plugins import TarmacPlugin

  class HelloWorldPlugin(TarmacPlugin):
      '''A basic plugin that prints "Hello World" when fired.'''


This is an entirely plausible/valid plugin.  It's worthless, it's true, but
it's still valid.  The plugin does need to be registered with before it can be
used.  For instance, in order to register the plugin to be fired before commit,
you would use the following code::

  from tarmac.hooks import tarmac_hooks

  tarmac_hooks['tarmac_pre_commit'].hook(
      HelloWorldPlugin(), 'HelloWorld plugin')


You can put this into helloworld.py and pop it into
`$HOME/.config/tarmac/plugins/``.  The plugin is now available at
``tarmac.plugins.helloworld.HelloWorldPlugin`` and is registered to be fired
after the merge and before the commit.  You can use this plugin to make sure
the merge creates a kosher tree and reject it if it doesn't make you happy.

Now that we have our hook registered and available, we can make it actually do
something!  Let's have print "Hello World!"  TarmacPlugins are merely
callables, the ``run`` method should be implemented.  For
HelloWorldPlugin, it would look like this::

  class HelloWorldPlugin(TarmacPlugin):
      '''A basic plugin that prints "Hello World" when fired.'''

      def run(self, command, target, source, proposal):
          print 'Hello World!'

Now when we run the plugin, it will print "Hello World!" before each commit.
This is a trivial example, but one that demonstrates how it works.  The
arguments to the plugin are explained below.

**command**
  The tarmac command.  For instance, a ``tarmac land`` call.

**target**
  An instance of ``tarmac.branch.Branch`` containing details about the target
  branch.

**source**
  An instance of ``tarmac.branch.Branch`` containing details about the source
  branch.

**proposal**
  The merge proposal that proposes the source branch for merge into the target.



Handling Errors
===============

If you are writing a plug-in to validate against some prerequisites for a
merge to be successful, you may wish to raise an exception if this criteria
goes unmet, within your plug-in, to prevent the successful merge of a branch.
The Tarmac merge command automatically handles exceptions. All you need to
do, is raise the right one. To do this, simply use TarmacMergeError, or
create your own exception class as a sub-class thereof. For example, if you
were writing a plug-in to run a test before committing a change, you might
define your exception like this:

  from tarmac.exceptions import TarmacMergeError


  class TestCommandFailed(TarmacMergeError):
      """The test command failed to complete successfully."""


And when you raise your exception to prevent the commit from happening, you
might do the following:

  message = u'The test command failed to complete successfully.'
  comment = (u'Tests failed to pass, with the following errors:'
             u'\n\n%(output)s' % {'output': test_output})
  raise TestCommandFailed(message, comment)

The TarmacMergeCommand exception takes two arguments. The first is a short
message summarizing what failed, and the second is a comment that would be
posted to the merge proposal on Launchpad, to let the developer know what
needs to be fixed in their branch. The ``message`` argument is similar to
a normal Python Exception message argument. However, in this case, it should
be kept to a brief summary of what failed, as the message will be appended
to another short string for writing to a log. The ``comment`` argument is
typically a longer message describing the issue in more detail. This comment
will be posted to the merge proposal on Launchpad, to inform the developer
of what went wrong during the merge of their branch. The merge proposal will
also be set back to the ``Needs Review`` status, to avoid having tarmac
attempt to merge the branch again, without having the issues resolved. If
no ``comment`` argument is supplied, the ``message`` argument will be used
for the comment when posting to Launchpad, instead.



Caveats
=======

Since Tarmac is still a young project, the API for plugins is subject to
drastic change in the next few versions of Tarmac, but is planned to be stable
when Tarmac reaches 1.0.