mup

Merge lp:~therve/mup/merge-proposal-support into lp:mup

Proposed by Thomas Herve
Status: Merged
Merge reported by: Gustavo Niemeyer
Merged at revision: not available
Proposed branch: lp:~therve/mup/merge-proposal-support
Merge into: lp:mup
Diff against target: 246 lines (+175/-1)
4 files modified
src/Makefile (+1/-0)
src/mup.app.src (+1/-0)
src/mup_launchpad.erl (+37/-1)
src/mup_mergetracking.erl (+136/-0)
To merge this branch: bzr merge lp:~therve/mup/merge-proposal-support
Reviewer Review Type Date Requested Status
Gustavo Niemeyer Approve
Review via email: mp+18639@code.launchpad.net
To post a comment you must log in.
Revision history for this message
Thomas Herve (therve) wrote :

This branch adds support for tracking merge proposals. Here is an example config:

{plugin, new_landscape_merges, mup_mergetracking, [
    {mup_launchpad_name, bugs_for_canonical},
    {targets, [{canonical, "#landscape"}]},
    {interval, 10},
    {project, "landscape"}
]}.

Revision history for this message
Gustavo Niemeyer (niemeyer) wrote :

That's been merged. Thank you!

review: Approve

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/Makefile'
2--- src/Makefile 2008-12-08 03:33:35 +0000
3+++ src/Makefile 2010-02-04 21:06:19 +0000
4@@ -20,6 +20,7 @@
5 mup_plugin_sup.erl \
6 mup_launchpad.erl \
7 mup_bugtracking.erl \
8+ mup_mergetracking.erl \
9 mup_directory.erl \
10 mup_publishbot.erl \
11 mup_util.erl \
12
13=== modified file 'src/mup.app.src'
14--- src/mup.app.src 2008-10-16 00:34:41 +0000
15+++ src/mup.app.src 2010-02-04 21:06:19 +0000
16@@ -13,6 +13,7 @@
17 mup_plugin_sup,
18 mup_launchpad,
19 mup_bugtracking,
20+ mup_mergetracking,
21 mup_directory,
22 mup_publishbot,
23 mup_util,
24
25=== modified file 'src/mup_launchpad.erl'
26--- src/mup_launchpad.erl 2009-03-02 00:32:41 +0000
27+++ src/mup_launchpad.erl 2010-02-04 21:06:19 +0000
28@@ -17,7 +17,8 @@
29
30 -module(mup_launchpad).
31 -behaviour(gen_server).
32--export([start_link/1, show_bug/4, show_bug/5]).
33+-export([start_link/1, show_bug/4, show_bug/5, show_merge_proposal/4,
34+ get_merge_proposals/2, get_object_value/2]).
35 -export([init/1, handle_call/3, handle_cast/2, handle_info/2,
36 terminate/2, code_change/3]).
37 -include("mup.hrl").
38@@ -37,11 +38,21 @@
39 show_bug(Pid, Prefix, Number, Server, Target) ->
40 gen_server:cast(Pid, {show_bug, Prefix, Number, Server, Target}).
41
42+show_merge_proposal(Pid, Merge, Server, Target) ->
43+ gen_server:cast(Pid, {show_merge_proposal, Merge, Server, Target}).
44+
45+get_merge_proposals(Pid, Project) ->
46+ gen_server:call(Pid, {get_merge_proposals_internal, Project}).
47+
48
49 init(Name) ->
50 {ok, Plugin} = mup_config:get_plugin(Name),
51 {ok, #state{plugin=Plugin}}.
52
53+handle_call({get_merge_proposals_internal, Project}, _From, State) ->
54+ Merges = get_merge_proposals_internal(Project, State),
55+ {reply, {ok, Merges}, State};
56+
57 handle_call(_Request, _From, State) ->
58 {reply, ok, State}.
59
60@@ -53,6 +64,10 @@
61 spawn(fun () -> send_bug(Prefix, Number, Server, Target, State) end),
62 {noreply, State};
63
64+handle_cast({show_merge_proposal, Merge, Server, Target}, State) ->
65+ spawn(fun () -> send_merge_proposal(Merge, Server, Target, State) end),
66+ {noreply, State};
67+
68 handle_cast({handle_message, #message{command='PRIVMSG'}=Message}, State) ->
69 case mup_message:match_channels(Message, get_option(channels, State)) of
70 true ->
71@@ -178,6 +193,22 @@
72 ok
73 end.
74
75+send_merge_proposal(Merge, Server, Target, State) ->
76+ AllowPrivate = get_option(private, false, State),
77+ IsPrivate = get_object_value("private", Merge),
78+ if
79+ AllowPrivate or not IsPrivate ->
80+ SourceBranchUrl = get_object_value("source_branch_link", Merge),
81+ [_, SourceBranchName] = string:tokens(binary_to_list(SourceBranchUrl), "~"),
82+ Status = binary_to_list(get_object_value("queue_status", Merge)),
83+ {ok, Pid} = mup_server_sup:find_server(Server),
84+ Command = io_lib:fwrite("PRIVMSG ~s Branch lp:~~~s: ~s",
85+ [Target, SourceBranchName, string:to_lower(Status)]),
86+ mup_server:send(Pid, Command);
87+ true ->
88+ ok
89+ end.
90+
91
92 get_bug_task_notes([Entry|Rest]) ->
93 [erlang:binary_to_list(get_object_value("bug_target_display_name", Entry))
94@@ -206,6 +237,11 @@
95 end.
96
97
98+get_merge_proposals_internal(Project, State) ->
99+ Collection = perform_launchpad_request([Project, "?ws.op=getMergeProposals"], State),
100+ get_object_value("entries", Collection).
101+
102+
103 perform_launchpad_request(UrlSuffix, State) ->
104 Plugin = State#state.plugin,
105 {MegaSecs, Secs, MicroSecs} = erlang:now(),
106
107=== added file 'src/mup_mergetracking.erl'
108--- src/mup_mergetracking.erl 1970-01-01 00:00:00 +0000
109+++ src/mup_mergetracking.erl 2010-02-04 21:06:19 +0000
110@@ -0,0 +1,136 @@
111+% Mup IRC Bot
112+%
113+% Copyright (C) 2008 Gustavo Niemeyer
114+%
115+% This program is free software: you can redistribute it and/or modify
116+% it under the terms of the GNU Affero General Public License as
117+% published by the Free Software Foundation, either version 3 of the
118+% License, or (at your option) any later version.
119+%
120+% This program is distributed in the hope that it will be useful,
121+% but WITHOUT ANY WARRANTY; without even the implied warranty of
122+% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
123+% GNU Affero General Public License for more details.
124+%
125+% You should have received a copy of the GNU Affero General Public License
126+% along with this program. If not, see <http://www.gnu.org/licenses/>.
127+
128+-module(mup_mergetracking).
129+-behaviour(gen_server).
130+-export([start_link/1]).
131+-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
132+ terminate/2, code_change/3]).
133+-include("mup.hrl").
134+-include_lib("eunit/include/eunit.hrl").
135+
136+
137+-record(state,
138+ {plugin,
139+ merges,
140+ update_timer}).
141+
142+start_link(Name) ->
143+ gen_server:start_link(?MODULE, Name, []).
144+
145+init(Name) ->
146+ {ok, Plugin} = mup_config:get_plugin(Name),
147+ {ok, schedule_update(#state{plugin=Plugin})}.
148+
149+handle_call(_Request, _From, State) ->
150+ {reply, {error, bad_request}, State}.
151+
152+handle_cast({handle_message, _Message}, State) ->
153+ {noreply, State};
154+
155+handle_cast(reconfig, State) ->
156+ case mup_config:get_plugin((State#state.plugin)#plugin.name) of
157+ {ok, Plugin} ->
158+ {noreply, State#state{plugin=Plugin}};
159+ undefined ->
160+ {stop, normal, State}
161+ end.
162+
163+merge_objects_to_dict(Merges) ->
164+ merge_objects_to_dict(Merges, dict:new()).
165+
166+merge_objects_to_dict([], Dict) ->
167+ Dict;
168+
169+merge_objects_to_dict([Merge | Tail], Dict) ->
170+ MergeUrl = mup_launchpad:get_object_value("self_link", Merge),
171+ Status = mup_launchpad:get_object_value("queue_status", Merge),
172+ merge_objects_to_dict(Tail, dict:store(MergeUrl, Status, Dict)).
173+
174+handle_info(update, State) ->
175+ LaunchpadPid = get_mup_launchpad_pid(State),
176+ Project = get_option(project, "", State),
177+ {ok, NewMerges} = mup_launchpad:get_merge_proposals(LaunchpadPid, Project),
178+ NewMergesAsDict = merge_objects_to_dict(NewMerges),
179+ case State#state.merges of
180+ undefined ->
181+ ok;
182+ OldMerges ->
183+ Channels = get_option(targets, [], State),
184+ show_merges(NewMerges, OldMerges, Channels, LaunchpadPid)
185+ end,
186+ {noreply, schedule_update(State#state{merges=NewMergesAsDict})};
187+
188+handle_info(_Info, State) ->
189+ {noreply, State}.
190+
191+terminate(_Reason, _State) ->
192+ ok.
193+
194+code_change(_OldVsn, State, _Extra) ->
195+ {ok, State}.
196+
197+
198+get_option(Key, State) ->
199+ mup_util:option(Key, (State#state.plugin)#plugin.options).
200+
201+get_option(Key, Default, State) ->
202+ mup_util:option(Key, (State#state.plugin)#plugin.options, Default).
203+
204+get_mup_launchpad_pid(State) ->
205+ case get_option(mup_launchpad_name, State) of
206+ undefined ->
207+ throw({missing_option, mup_launchpad_name});
208+ Name ->
209+ {ok, LaunchpadPid} = mup_plugin_sup:find_plugin(Name),
210+ LaunchpadPid
211+ end.
212+
213+
214+schedule_update(State) ->
215+ case State#state.update_timer of
216+ undefined ->
217+ ok;
218+ Timer ->
219+ erlang:cancel_timer(Timer)
220+ end,
221+ Interval = get_option(interval, 300, State) * 1000,
222+ State#state{update_timer=erlang:send_after(Interval, self(), update)}.
223+
224+
225+show_merges([Merge|Rest], OldMerges, Channels, LaunchpadPid) ->
226+ MergeUrl = mup_launchpad:get_object_value("self_link", Merge),
227+ NewStatus = mup_launchpad:get_object_value("queue_status", Merge),
228+ case dict:find(MergeUrl, OldMerges) of
229+ {ok, NewStatus} ->
230+ ok;
231+ error ->
232+ show_merge(Merge, Channels, LaunchpadPid);
233+ {ok, OldStatus} ->
234+ show_merge(Merge, Channels, LaunchpadPid)
235+ end,
236+ show_merges(Rest, OldMerges, Channels, LaunchpadPid);
237+
238+show_merges([], _OldMerges, _Channels, _LaunchpadPid) ->
239+ ok.
240+
241+show_merge(Merge, [{Server, Channel}|Rest], LaunchpadPid) ->
242+ mup_launchpad:show_merge_proposal(LaunchpadPid, Merge, Server, Channel),
243+ show_merge(Merge, Rest, LaunchpadPid);
244+
245+show_merge(_Merge, [], _LaunchpadPid) ->
246+ ok.

Subscribers

People subscribed via source and target branches

to all changes: