Merge lp:~jtv/gwacl/unexport-x509 into lp:gwacl

Proposed by Jeroen T. Vermeulen
Status: Merged
Approved by: Jeroen T. Vermeulen
Approved revision: 62
Merged at revision: 63
Proposed branch: lp:~jtv/gwacl/unexport-x509
Merge into: lp:gwacl
Diff against target: 518 lines (+73/-73)
6 files modified
managementapi.go (+2/-2)
managementapi_test.go (+7/-7)
x509dispatcher.go (+20/-20)
x509dispatcher_test.go (+7/-7)
x509session.go (+9/-9)
x509session_test.go (+28/-28)
To merge this branch: bzr merge lp:~jtv/gwacl/unexport-x509
Reviewer Review Type Date Requested Status
Julian Edwards (community) Approve
Review via email: mp+155409@code.launchpad.net

Commit message

Un-export the X509 classes. They're an implementation detail, completely hidden from the gwacl API.

Description of the change

Cleaning up the public API that we expose for gwacl.

I regret the size of this diff. Just un-exporting some identifiers is a huge amount of pointless diff in Go. I figured for that very reason it'd be best to get this behind us as soon as possible, with a minimum of development going on for it to interfere with.

For what it's worth, the un-exporting of these items is the *only* thing that happens in this branch. It's a mechanical change: X509Request / X509Response / X509Session structs become x509Request / x509Response / x509Session respectively, and their constructors NewX509* become newX509* (insofar as they weren't lower-cased already).

Jeroen

To post a comment you must log in.
Revision history for this message
Julian Edwards (julian-edwards) wrote :

"Just un-exporting some identifiers is a huge amount of pointless diff in Go"

Sigh :/

review: Approve
Revision history for this message
Julian Edwards (julian-edwards) wrote :

Attempt to merge into lp:gwacl failed due to conflicts:

text conflict in managementapi_test.go

Revision history for this message
Julian Edwards (julian-edwards) wrote :

There are additional revisions which have not been approved in review. Please seek review and approval of these new revisions.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'managementapi.go'
2--- managementapi.go 2013-03-25 02:10:02 +0000
3+++ managementapi.go 2013-03-26 08:56:20 +0000
4@@ -8,13 +8,13 @@
5 )
6
7 type ManagementAPI struct {
8- session *X509Session
9+ session *x509Session
10 }
11
12 // NewManagementAPI creates an object used to interact with Windows Azure's API.
13 // http://msdn.microsoft.com/en-us/library/windowsazure/ff800682.aspx
14 func NewManagementAPI(subscriptionId string, certFile string) (*ManagementAPI, error) {
15- session, err := NewX509Session(subscriptionId, certFile)
16+ session, err := newX509Session(subscriptionId, certFile)
17 if err != nil {
18 return nil, err
19 }
20
21=== modified file 'managementapi_test.go'
22--- managementapi_test.go 2013-03-26 07:00:46 +0000
23+++ managementapi_test.go 2013-03-26 08:56:20 +0000
24@@ -21,7 +21,7 @@
25 api, err := NewManagementAPI(subscriptionId, certFile)
26
27 c.Assert(err, IsNil)
28- session, err := NewX509Session(subscriptionId, certFile)
29+ session, err := newX509Session(subscriptionId, certFile)
30 c.Assert(api.session.subscriptionId, DeepEquals, session.subscriptionId)
31 c.Assert(api.session.certFile, DeepEquals, session.certFile)
32 }
33@@ -37,20 +37,20 @@
34 // setUpDispatcher sets up a request dispatcher that:
35 // - records requests
36 // - returns empty responses
37-func (suite *managementAPISuite) setUpDispatcher() *[]*X509Request {
38- fixedResponse := X509Response{
39+func (suite *managementAPISuite) setUpDispatcher() *[]*x509Request {
40+ fixedResponse := x509Response{
41 StatusCode: http.StatusOK,
42 Body: []byte{},
43 }
44 rigFixedResponseDispatcher(&fixedResponse)
45- recordedRequests := make([]*X509Request, 0)
46+ recordedRequests := make([]*x509Request, 0)
47 rigRecordingDispatcher(&recordedRequests)
48 return &recordedRequests
49 }
50
51 // checkRequest asserts that the given slice contains one request, with the
52 // given characteristics.
53-func checkRequest(c *C, recordedRequests *[]*X509Request, URL string, payload []byte, Method string) {
54+func checkRequest(c *C, recordedRequests *[]*x509Request, URL string, payload []byte, Method string) {
55 requests := *recordedRequests
56 c.Assert(len(requests), Equals, 1)
57 request := requests[0]
58@@ -128,8 +128,8 @@
59
60 func (suite *managementAPISuite) TestAddStorageAccount(c *C) {
61 api := suite.makeAPI(c)
62- rigFixedResponseDispatcher(&X509Response{StatusCode: http.StatusAccepted})
63- recordedRequests := make([]*X509Request, 0)
64+ rigFixedResponseDispatcher(&x509Response{StatusCode: http.StatusAccepted})
65+ recordedRequests := make([]*x509Request, 0)
66 rigRecordingDispatcher(&recordedRequests)
67 cssi := NewCreateStorageServiceInputWithLocation("name", "label", "East US")
68
69
70=== modified file 'x509dispatcher.go'
71--- x509dispatcher.go 2013-03-22 02:52:32 +0000
72+++ x509dispatcher.go 2013-03-26 08:56:20 +0000
73@@ -10,7 +10,7 @@
74 "net/textproto"
75 )
76
77-type X509Request struct {
78+type x509Request struct {
79 APIVersion string
80 Method string
81 URL string
82@@ -28,20 +28,20 @@
83 // baseAPIVersion is the default Azure API version to use.
84 const baseAPIVersion = "2012-03-01"
85
86-// newX509RequestGET initializes an X509Request for a GET. You may still need
87+// newX509RequestGET initializes an x509Request for a GET. You may still need
88 // to set further values.
89-func newX509RequestGET(url string) *X509Request {
90- return &X509Request{
91+func newX509RequestGET(url string) *x509Request {
92+ return &x509Request{
93 Method: "GET",
94 URL: url,
95 APIVersion: baseAPIVersion,
96 }
97 }
98
99-// newX509RequestPOST initializes an X509Request for a POST. You may still
100+// newX509RequestPOST initializes an x509Request for a POST. You may still
101 // need to set further values.
102-func newX509RequestPOST(url string, payload []byte, contentType string) *X509Request {
103- return &X509Request{
104+func newX509RequestPOST(url string, payload []byte, contentType string) *x509Request {
105+ return &x509Request{
106 Method: "POST",
107 URL: url,
108 APIVersion: baseAPIVersion,
109@@ -50,19 +50,19 @@
110 }
111 }
112
113-// newX509RequestDELETE initializes an X509Request for a DELETE.
114-func newX509RequestDELETE(url string) *X509Request {
115- return &X509Request{
116+// newX509RequestDELETE initializes an x509Request for a DELETE.
117+func newX509RequestDELETE(url string) *x509Request {
118+ return &x509Request{
119 Method: "DELETE",
120 URL: url,
121 APIVersion: baseAPIVersion,
122 }
123 }
124
125-// newX509RequestPUT initializes an X509Request for a PUT. You may still
126+// newX509RequestPUT initializes an x509Request for a PUT. You may still
127 // need to set further values.
128-func newX509RequestPUT(url string, payload []byte) *X509Request {
129- return &X509Request{
130+func newX509RequestPUT(url string, payload []byte) *x509Request {
131+ return &x509Request{
132 Method: "PUT",
133 URL: url,
134 APIVersion: baseAPIVersion,
135@@ -70,7 +70,7 @@
136 }
137 }
138
139-type X509Response struct {
140+type x509Response struct {
141 StatusCode int
142 // TODO: What exactly do we get back? How will we know its encoding?
143 Body []byte
144@@ -78,8 +78,8 @@
145 Header http.Header
146 }
147
148-func newX509Response() *X509Response {
149- return &X509Response{
150+func newX509Response() *x509Response {
151+ return &x509Response{
152 Body: make([]byte, 0),
153 RawHeader: make([]byte, 0),
154 }
155@@ -120,7 +120,7 @@
156
157 // parseHeader parses the raw header as stored in RawHeader, and uses it to
158 // initialize Header.
159-func (response *X509Response) parseHeader() error {
160+func (response *x509Response) parseHeader() error {
161 rawHeader := stripPreliminaryResponses(response.RawHeader)
162 mimeHeader, err := stripResponseLine(rawHeader)
163 if err != nil {
164@@ -141,7 +141,7 @@
165 return nil
166 }
167
168-func performX509CurlRequest(session *X509Session, request *X509Request) (*X509Response, error) {
169+func performX509CurlRequest(session *x509Session, request *x509Request) (*x509Response, error) {
170 if verbose {
171 log.Println("Performing request")
172 log.Println("Request url: " + request.URL)
173@@ -181,7 +181,7 @@
174 // makeCurlRequest produces a curl.CURL representing the request.
175 // Clean up the request by calling its Cleanup() method after you're done
176 // with it.
177-func (request *X509Request) makeCurlRequest(session *X509Session, response *X509Response) *curl.CURL {
178+func (request *x509Request) makeCurlRequest(session *x509Session, response *x509Response) *curl.CURL {
179 ch := curl.EasyInit()
180
181 ch.Setopt(curl.OPT_SSLCERT, session.certFile)
182@@ -230,7 +230,7 @@
183
184 // setCurlHTTPMethod sets up a CURL object to perform an HTTP request of
185 // the HTTP method (GET, POST, etc.) appropriate for the request.
186-func (request *X509Request) setCurlHTTPMethod(ch *curl.CURL) {
187+func (request *x509Request) setCurlHTTPMethod(ch *curl.CURL) {
188 switch request.Method {
189 case "GET":
190 // Nothing to be done. This is the default.
191
192=== modified file 'x509dispatcher_test.go'
193--- x509dispatcher_test.go 2013-03-22 02:06:22 +0000
194+++ x509dispatcher_test.go 2013-03-26 08:56:20 +0000
195@@ -30,7 +30,7 @@
196 // An HTTP header contains a response line followed by a MIME header, which
197 // parseHeader processes.
198 func (*X509DispatcherSuite) TestParseHeaderParsesHTTPHeader(c *C) {
199- response := X509Response{}
200+ response := x509Response{}
201 text := "HTTP/1.1 200 OK\r\nCache-Control: no-cache\r\n\r\n"
202 response.RawHeader = []byte(text)
203
204@@ -43,7 +43,7 @@
205 // An HTTP response actually contains a sequence of HTTP headers, and
206 // parseHeader only uses the final one.
207 func (*X509DispatcherSuite) TestParseHeaderParsesContinueResponse(c *C) {
208- response := X509Response{}
209+ response := x509Response{}
210 text := "HTTP/1.1 100 Continue\r\n\r\nHTTP/1.1 202 Accepted\r\nCache-Control: no-cache\r\n\r\n"
211 response.RawHeader = []byte(text)
212
213@@ -58,7 +58,7 @@
214 server := makeRecordingHTTPServer(httpRequests, http.StatusOK, nil)
215 defer server.Close()
216 // No real certificate needed since we're testing on http, not https.
217- session, err := NewX509Session("subscriptionid", "cert.pem")
218+ session, err := newX509Session("subscriptionid", "cert.pem")
219 c.Assert(err, IsNil)
220 path := "/foo/bar"
221 request := newX509RequestGET(server.URL + path)
222@@ -80,7 +80,7 @@
223 server := makeRecordingHTTPServer(httpRequests, http.StatusOK, responseBody)
224 defer server.Close()
225 // No real certificate needed since we're testing on http, not https.
226- session, err := NewX509Session("subscriptionid", "cert.pem")
227+ session, err := newX509Session("subscriptionid", "cert.pem")
228 c.Assert(err, IsNil)
229 path := "/foo/bar"
230 request := newX509RequestPOST(server.URL+path, requestBody, requestContentType)
231@@ -102,7 +102,7 @@
232 server := makeRecordingHTTPServer(httpRequests, http.StatusOK, []byte{})
233 defer server.Close()
234 // No real certificate needed since we're testing on http, not https.
235- session, err := NewX509Session("subscriptionid", "cert.pem")
236+ session, err := newX509Session("subscriptionid", "cert.pem")
237 c.Assert(err, IsNil)
238 path := "/foo/bar"
239 request := newX509RequestDELETE(server.URL + path)
240@@ -123,7 +123,7 @@
241 server := makeRecordingHTTPServer(httpRequests, http.StatusOK, responseBody)
242 defer server.Close()
243 // No real certificate needed since we're testing on http, not https.
244- session, err := NewX509Session("subscriptionid", "cert.pem")
245+ session, err := newX509Session("subscriptionid", "cert.pem")
246 c.Assert(err, IsNil)
247 path := "/foo/bar"
248 request := newX509RequestPUT(server.URL+path, requestBody)
249@@ -149,7 +149,7 @@
250 serveMux.HandleFunc("/", returnRequest)
251 server := httptest.NewServer(serveMux)
252 defer server.Close()
253- session, err := NewX509Session("subscriptionid", "cert.pem")
254+ session, err := newX509Session("subscriptionid", "cert.pem")
255 c.Assert(err, IsNil)
256 path := "/foo/bar"
257 request := newX509RequestGET(server.URL + path)
258
259=== modified file 'x509session.go'
260--- x509session.go 2013-03-20 23:53:03 +0000
261+++ x509session.go 2013-03-26 08:56:20 +0000
262@@ -8,15 +8,15 @@
263 "net/http"
264 )
265
266-type X509Session struct {
267+type x509Session struct {
268 subscriptionId string
269 certFile string
270 }
271
272-// NewX509Session creates and returns a new X509Session based on credentials
273+// newX509Session creates and returns a new x509Session based on credentials
274 // and X509 certificate files.
275-func NewX509Session(subscriptionId string, certFile string) (*X509Session, error) {
276- return &X509Session{subscriptionId: subscriptionId, certFile: certFile}, nil
277+func newX509Session(subscriptionId string, certFile string) (*x509Session, error) {
278+ return &x509Session{subscriptionId: subscriptionId, certFile: certFile}, nil
279 }
280
281 var AZURE_URL = "https://management.core.windows.net/"
282@@ -43,7 +43,7 @@
283
284 // getServerError returns a ServerError matching the given server response
285 // status, or nil if the server response indicates success.
286-func (session *X509Session) getServerError(status int, description string) error {
287+func (session *x509Session) getServerError(status int, description string) error {
288 if status < http.StatusOK || status >= http.StatusMultipleChoices {
289 failure := fmt.Errorf("%s (http status code %d)", description, status)
290 return &ServerError{error: failure, StatusCode: status}
291@@ -55,7 +55,7 @@
292 // It returns the response body and/or an error. If the error is a
293 // ServerError, the returned body will be the one received from the server.
294 // For any other kind of error, the returned body will be nil.
295-func (session *X509Session) get(url string) ([]byte, error) {
296+func (session *x509Session) get(url string) ([]byte, error) {
297 fullUrl := composeURL(url, session.subscriptionId)
298 request := newX509RequestGET(fullUrl)
299 response, err := _X509Dispatcher(session, request)
300@@ -70,7 +70,7 @@
301 // It returns the response body and/or an error. If the error is a
302 // ServerError, the returned body will be the one received from the server.
303 // For any other kind of error, the returned body will be nil.
304-func (session *X509Session) post(url string, body []byte, contentType string) ([]byte, error) {
305+func (session *x509Session) post(url string, body []byte, contentType string) ([]byte, error) {
306 fullUrl := composeURL(url, session.subscriptionId)
307 request := newX509RequestPOST(fullUrl, body, contentType)
308 response, err := _X509Dispatcher(session, request)
309@@ -82,7 +82,7 @@
310 }
311
312 // delete performs a DELETE request to the Azure management API.
313-func (session *X509Session) delete(url string) error {
314+func (session *x509Session) delete(url string) error {
315 fullUrl := composeURL(url, session.subscriptionId)
316 request := newX509RequestDELETE(fullUrl)
317 response, err := _X509Dispatcher(session, request)
318@@ -93,7 +93,7 @@
319 }
320
321 // put performs a PUT request to the Azure management API.
322-func (session *X509Session) put(url string, body []byte) error {
323+func (session *x509Session) put(url string, body []byte) error {
324 fullUrl := composeURL(url, session.subscriptionId)
325 request := newX509RequestPUT(fullUrl, body)
326 response, err := _X509Dispatcher(session, request)
327
328=== modified file 'x509session_test.go'
329--- x509session_test.go 2013-03-20 23:53:03 +0000
330+++ x509session_test.go 2013-03-26 08:56:20 +0000
331@@ -18,7 +18,7 @@
332 )
333
334 type X509SessionSuite struct {
335- oldDispatcher func(*X509Session, *X509Request) (*X509Response, error)
336+ oldDispatcher func(*x509Session, *x509Request) (*x509Response, error)
337 }
338
339 var _ = Suite(&X509SessionSuite{})
340@@ -29,9 +29,9 @@
341 // If you also want the dispatcher to return a particular result, rig it for
342 // that result first (using one of the other rig...Dispatcher functions) and
343 // then chain the recording dispatcher in front of it.
344-func rigRecordingDispatcher(record *[]*X509Request) {
345+func rigRecordingDispatcher(record *[]*x509Request) {
346 previousDispatcher := _X509Dispatcher
347- _X509Dispatcher = func(session *X509Session, request *X509Request) (*X509Response, error) {
348+ _X509Dispatcher = func(session *x509Session, request *x509Request) (*x509Response, error) {
349 *record = append(*record, request)
350 return previousDispatcher(session, request)
351 }
352@@ -39,8 +39,8 @@
353
354 // rigFixedResponseDispatcher sets up a request dispatcher that always returns
355 // a prepared response.
356-func rigFixedResponseDispatcher(response *X509Response) {
357- _X509Dispatcher = func(*X509Session, *X509Request) (*X509Response, error) {
358+func rigFixedResponseDispatcher(response *x509Response) {
359+ _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) {
360 return response, nil
361 }
362 }
363@@ -48,7 +48,7 @@
364 // rigFailingDispatcher sets up a request dispatcher that returns a given
365 // error.
366 func rigFailingDispatcher(failure error) {
367- _X509Dispatcher = func(*X509Session, *X509Request) (*X509Response, error) {
368+ _X509Dispatcher = func(*x509Session, *x509Request) (*x509Response, error) {
369 return nil, failure
370 }
371 }
372@@ -125,14 +125,14 @@
373 }
374
375 func (suite *X509SessionSuite) TestNewX509SessionCreation(c *C) {
376- _, err := NewX509Session("subscriptionid", "azure.pem")
377+ _, err := newX509Session("subscriptionid", "azure.pem")
378 c.Assert(err, IsNil)
379 }
380
381 func (suite *X509SessionSuite) TestGetServerErrorProducesServerError(c *C) {
382 msg := "huhwhat"
383 status := http.StatusNotFound
384- session, err := NewX509Session("subscriptionid", "azure.pem")
385+ session, err := newX509Session("subscriptionid", "azure.pem")
386 c.Assert(err, IsNil)
387
388 err = session.getServerError(status, msg)
389@@ -148,7 +148,7 @@
390 http.StatusOK,
391 http.StatusNoContent,
392 }
393- session, err := NewX509Session("subscriptionid", "azure.pem")
394+ session, err := newX509Session("subscriptionid", "azure.pem")
395 c.Assert(err, IsNil)
396
397 for _, status := range goodCodes {
398@@ -166,7 +166,7 @@
399 http.StatusInternalServerError,
400 http.StatusNotImplemented,
401 }
402- session, err := NewX509Session("subscriptionid", "azure.pem")
403+ session, err := newX509Session("subscriptionid", "azure.pem")
404 c.Assert(err, IsNil)
405
406 for _, status := range badCodes {
407@@ -177,15 +177,15 @@
408 func (suite *X509SessionSuite) TestGetIssuesRequest(c *C) {
409 subscriptionID := "subscriptionID"
410 uri := "resource"
411- session, err := NewX509Session(subscriptionID, "cert.pem")
412+ session, err := newX509Session(subscriptionID, "cert.pem")
413 c.Assert(err, IsNil)
414 // Record incoming requests, and have them return a given reply.
415- fixedResponse := X509Response{
416+ fixedResponse := x509Response{
417 StatusCode: http.StatusOK,
418 Body: []byte("Response body"),
419 }
420 rigFixedResponseDispatcher(&fixedResponse)
421- recordedRequests := make([]*X509Request, 0)
422+ recordedRequests := make([]*x509Request, 0)
423 rigRecordingDispatcher(&recordedRequests)
424
425 receivedBody, err := session.get(uri)
426@@ -199,7 +199,7 @@
427 }
428
429 func (suite *X509SessionSuite) TestGetReportsClientSideError(c *C) {
430- session, err := NewX509Session("subscriptionid", "cert.pem")
431+ session, err := newX509Session("subscriptionid", "cert.pem")
432 msg := "could not dispatch request"
433 rigFailingDispatcher(fmt.Errorf(msg))
434
435@@ -211,8 +211,8 @@
436 }
437
438 func (suite *X509SessionSuite) TestGetReportsServerSideError(c *C) {
439- session, err := NewX509Session("subscriptionid", "cert.pem")
440- fixedResponse := X509Response{
441+ session, err := newX509Session("subscriptionid", "cert.pem")
442+ fixedResponse := x509Response{
443 StatusCode: http.StatusForbidden,
444 Body: []byte("Body"),
445 }
446@@ -231,15 +231,15 @@
447 uri := "resource"
448 requestBody := []byte("Request body")
449 requestContentType := "bogusContentType"
450- session, err := NewX509Session(subscriptionID, "cert.pem")
451+ session, err := newX509Session(subscriptionID, "cert.pem")
452 c.Assert(err, IsNil)
453 // Record incoming requests, and have them return a given reply.
454- fixedResponse := X509Response{
455+ fixedResponse := x509Response{
456 StatusCode: http.StatusOK,
457 Body: []byte("Response body"),
458 }
459 rigFixedResponseDispatcher(&fixedResponse)
460- recordedRequests := make([]*X509Request, 0)
461+ recordedRequests := make([]*x509Request, 0)
462 rigRecordingDispatcher(&recordedRequests)
463
464 receivedBody, err := session.post(uri, requestBody, requestContentType)
465@@ -255,7 +255,7 @@
466 }
467
468 func (suite *X509SessionSuite) TestPostReportsClientSideError(c *C) {
469- session, err := NewX509Session("subscriptionid", "cert.pem")
470+ session, err := newX509Session("subscriptionid", "cert.pem")
471 msg := "could not dispatch request"
472 rigFailingDispatcher(fmt.Errorf(msg))
473
474@@ -267,8 +267,8 @@
475 }
476
477 func (suite *X509SessionSuite) TestPostReportsServerSideError(c *C) {
478- session, err := NewX509Session("subscriptionid", "cert.pem")
479- fixedResponse := X509Response{
480+ session, err := newX509Session("subscriptionid", "cert.pem")
481+ fixedResponse := x509Response{
482 StatusCode: http.StatusForbidden,
483 Body: []byte("Body"),
484 }
485@@ -285,12 +285,12 @@
486 func (suite *X509SessionSuite) TestDeleteIssuesRequest(c *C) {
487 subscriptionID := "subscriptionID"
488 uri := "resource"
489- session, err := NewX509Session(subscriptionID, "cert.pem")
490+ session, err := newX509Session(subscriptionID, "cert.pem")
491 c.Assert(err, IsNil)
492 // Record incoming requests, and have them return a given reply.
493- fixedResponse := X509Response{StatusCode: http.StatusOK}
494+ fixedResponse := x509Response{StatusCode: http.StatusOK}
495 rigFixedResponseDispatcher(&fixedResponse)
496- recordedRequests := make([]*X509Request, 0)
497+ recordedRequests := make([]*x509Request, 0)
498 rigRecordingDispatcher(&recordedRequests)
499
500 err = session.delete(uri)
501@@ -306,14 +306,14 @@
502 subscriptionID := "subscriptionID"
503 uri := "resource"
504 requestBody := []byte("Request body")
505- session, err := NewX509Session(subscriptionID, "cert.pem")
506+ session, err := newX509Session(subscriptionID, "cert.pem")
507 c.Assert(err, IsNil)
508 // Record incoming requests, and have them return a given reply.
509- fixedResponse := X509Response{
510+ fixedResponse := x509Response{
511 StatusCode: http.StatusOK,
512 }
513 rigFixedResponseDispatcher(&fixedResponse)
514- recordedRequests := make([]*X509Request, 0)
515+ recordedRequests := make([]*x509Request, 0)
516 rigRecordingDispatcher(&recordedRequests)
517
518 err = session.put(uri, requestBody)

Subscribers

People subscribed via source and target branches