return empty string in case of 404 also for package
[meego-infrastructure-tools:boss-participant-getchangelog.git] / get_relevant_changelog.py
1 #!/usr/bin/python
2 """ Quality check participant """
3
4 import difflib
5 import re
6 from buildservice import BuildService
7 from urllib2 import HTTPError
8
9 _blankre = re.compile(r"^\W*$")
10
11 def get_relevant_changelog(src_chlog, dst_chlog):
12     """ Diff two changelogs and return the list of lines that are only in
13         the source changelog """
14
15     relchlog = []
16     # compare source changelog to dest changelog
17     diff_txt = difflib.unified_diff(src_chlog.splitlines(),
18                                     dst_chlog.splitlines())
19     # Convert the diff text to a list of lines discarding the diff header
20     diff_list = list(diff_txt)[3:]
21     # Logic to compare changelogs and extract relevant entries 
22     for line in diff_list:
23         if line.startswith("+"):
24             entry = line.replace("+", "", 1)
25             if entry != "":
26                 relchlog.append(entry)
27         elif line.startswith("-"):
28             # As soon as we hit a removed line we skip out
29             break
30         else:
31             continue
32
33     # Now take the list of lines and create a list of changelog
34     # entries by splitting on blanks
35     ces = []
36     ce = ""
37     for line in relchlog:
38         line = line.rstrip('\r\n') # Apparently this is needed
39         # line=_to_unicode(line) # Needed?
40         if _blankre.match(line):
41             ces.append(ce)
42             ce = ""
43             continue # without adding the blank to the ce
44         ce += line + "\n"
45     # If we have any lines left they're a ce
46     if ce:
47         ces.append(ce)
48  
49     return ces
50
51 class ParticipantHandler(object):
52
53     """ Participant class as defined by the SkyNET API """
54
55     def __init__(self):
56         self.obs = None
57         self.oscrc = None
58
59     def handle_wi_control(self, ctrl):
60         """ job control thread """
61         pass
62     
63     def handle_lifecycle_control(self, ctrl):
64         """ participant control thread """
65         if ctrl.message == "start":
66             if ctrl.config.has_option("obs", "oscrc"):
67                 self.oscrc = ctrl.config.get("obs", "oscrc")
68     
69     def setup_obs(self, namespace):
70         """ setup the Buildservice instance using the namespace as an alias
71             to the apiurl """
72
73         self.obs = BuildService(oscrc=self.oscrc, apiurl=namespace)
74
75     def get_changes_file(self, prj, pkg, rev=None):
76
77
78         """ Get a package's changes file """
79
80         changelog = ""
81         try:
82             file_list = self.obs.getPackageFileList(prj, pkg, revision=rev)
83             for fil in file_list:
84                 if fil.endswith(".changes"):
85                     changelog = self.obs.getFile(prj, pkg, fil, revision=rev)
86         except HTTPError, e:
87             if e.code == 404:
88                 pass
89
90         return changelog
91
92     def get_relevant_changelogs(self, wid):
93
94         """ Get relevant changelog entries for the actions of an OBS request
95             and enrich each action's data structure with them """
96
97         wid.result = False
98         actions = wid.fields.ev.actions
99
100         if not actions:
101             wid.__error__ = "A needed field does not exist."
102             return
103
104         use_rev = False
105         if wid.params.compare and wid.params.compare == "last_revision":
106             use_rev = True
107
108         for i in xrange(len(actions)):
109             src_chlog = ""
110             if use_rev:
111                 # get commit history
112                 commit_log = self.obs.getCommitLog(actions[i]['targetproject'],
113                                                    actions[i]['targetpackage'])
114                 # use the second last commit revision if available
115                 if len(commit_log) > 1 :
116                     src_chlog = self.get_changes_file(actions[i]['targetproject'],
117                                                       actions[i]['targetpackage'],
118                                                       str( commit_log[1][0] ))
119             else:
120                 src_chlog = self.get_changes_file(actions[i]['sourceproject'],
121                                                   actions[i]['sourcepackage'],
122                                                   actions[i]['sourcerevision'])
123
124             dst_chlog = self.get_changes_file(actions[i]['targetproject'],
125                                               actions[i]['targetpackage'])
126
127             rel_chlog = get_relevant_changelog(src_chlog, dst_chlog)
128
129             if rel_chlog:
130                 actions[i]["relevant_changelog"] = rel_chlog
131
132
133         wid.fields.ev.actions = actions
134         wid.result = True
135
136     def handle_wi(self, wid):
137
138         """ actual job thread """
139
140         # We may want to examine the fields structure
141         if wid.fields.debug_dump or wid.params.debug_dump:
142             print wid.dump() 
143
144         self.setup_obs(wid.fields.ev.namespace)
145         self.get_relevant_changelogs(wid)