[whimsy] branch master updated: only include member info if it is not empty

2016-04-06 Thread rubys
This is an automated email from the ASF dual-hosted git repository.

rubys pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  71fe9e9   only include member info if it is not empty
71fe9e9 is described below

commit 71fe9e95583a8465a5bf987c9baa49c76637536f
Author: Sam Ruby 
AuthorDate: Wed Apr 6 08:30:15 2016 -0400

only include member info if it is not empty
---
 www/roster/models/committer.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www/roster/models/committer.rb b/www/roster/models/committer.rb
index 67f1b05..7a48803 100644
--- a/www/roster/models/committer.rb
+++ b/www/roster/models/committer.rb
@@ -109,7 +109,7 @@ class Committer
 end
   end
 
-  response[:member] = member
+  response[:member] = member unless member.empty?
 
 end
 

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].


[whimsy] branch master updated: avoid removing people who are not there

2016-04-06 Thread rubys
This is an automated email from the ASF dual-hosted git repository.

rubys pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  5631c57   avoid removing people who are not there
5631c57 is described below

commit 5631c57294729efe4b54ba7e3fa74849f67f03ab
Author: Sam Ruby 
AuthorDate: Wed Apr 6 08:46:12 2016 -0400

avoid removing people who are not there

and avoid adding people who already are
---
 lib/whimsy/asf/ldap.rb | 14 --
 1 file changed, 8 insertions(+), 6 deletions(-)

diff --git a/lib/whimsy/asf/ldap.rb b/lib/whimsy/asf/ldap.rb
index 3eee18a..3201d04 100644
--- a/lib/whimsy/asf/ldap.rb
+++ b/lib/whimsy/asf/ldap.rb
@@ -467,7 +467,8 @@ module ASF
 end
 
 def remove(people)
-  people = Array(people).map(&:id)
+  people = (Array(people) & members).map(&:id)
+  return if people.empty?
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'memberUid', people)
   ASF.ldap.modify(self.dn, [mod])
 ensure
@@ -475,7 +476,8 @@ module ASF
 end
 
 def add(people)
-  people = Array(people).map(&:id)
+  people = (Array(people) - members).map(&:id)
+  return if people.empty?
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'memberUid', people)
   ASF.ldap.modify(self.dn, [mod])
 ensure
@@ -521,7 +523,7 @@ module ASF
 end
 
 def remove(people)
-  people = Array(people).map(&:dn)
+  people = Array(people & members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
 ensure
@@ -529,7 +531,7 @@ module ASF
 end
 
 def add(people)
-  people = Array(people).map(&:dn)
+  people = Array(people - members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
 ensure
@@ -575,14 +577,14 @@ module ASF
 end
 
 def remove(people)
-  people = Array(people).map(&:dn)
+  people = Array(people - members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
   @members = nil
 end
 
 def add(people)
-  people = Array(people).map(&:dn)
+  people = Array(people & members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
   @members = nil

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].


[whimsy] branch master updated: just to be sure, get a fresh member list

2016-04-06 Thread rubys
This is an automated email from the ASF dual-hosted git repository.

rubys pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  891cc39   just to be sure, get a fresh member list
891cc39 is described below

commit 891cc39d7e6fc6c6272aef723a212a720839cec7
Author: Sam Ruby 
AuthorDate: Wed Apr 6 08:50:47 2016 -0400

just to be sure, get a fresh member list
---
 lib/whimsy/asf/ldap.rb | 8 
 1 file changed, 8 insertions(+)

diff --git a/lib/whimsy/asf/ldap.rb b/lib/whimsy/asf/ldap.rb
index 3201d04..bece91c 100644
--- a/lib/whimsy/asf/ldap.rb
+++ b/lib/whimsy/asf/ldap.rb
@@ -467,6 +467,7 @@ module ASF
 end
 
 def remove(people)
+  @members = nil
   people = (Array(people) & members).map(&:id)
   return if people.empty?
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'memberUid', people)
@@ -476,6 +477,7 @@ module ASF
 end
 
 def add(people)
+  @members = nil
   people = (Array(people) - members).map(&:id)
   return if people.empty?
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'memberUid', people)
@@ -523,6 +525,7 @@ module ASF
 end
 
 def remove(people)
+  @members = nil
   people = Array(people & members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
@@ -531,6 +534,7 @@ module ASF
 end
 
 def add(people)
+  @members = nil
   people = Array(people - members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
@@ -577,16 +581,20 @@ module ASF
 end
 
 def remove(people)
+  @members = nil
   people = Array(people - members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_DELETE, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
+ensure
   @members = nil
 end
 
 def add(people)
+  @members = nil
   people = Array(people & members).map(&:dn)
   mod = ::LDAP::Mod.new(::LDAP::LDAP_MOD_ADD, 'member', people)
   ASF.ldap.modify(self.dn, [mod])
+ensure
   @members = nil
 end
   end

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].


[whimsy] branch master updated: update check signature email

2016-04-06 Thread rubys
This is an automated email from the ASF dual-hosted git repository.

rubys pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  66fdf83   update check signature email
66fdf83 is described below

commit 66fdf83b66f59f5c4c3d42464099138dcf4a9359
Author: Sam Ruby 
AuthorDate: Wed Apr 6 12:17:54 2016 -0400

update check signature email
---
 www/secmail/views/check-signature.js.rb | 5 -
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/www/secmail/views/check-signature.js.rb 
b/www/secmail/views/check-signature.js.rb
index fa06849..26f6939 100644
--- a/www/secmail/views/check-signature.js.rb
+++ b/www/secmail/views/check-signature.js.rb
@@ -83,7 +83,10 @@ class CheckSignature < React
   def request_upload()
 destination = @@headers.From
 subject = "Re: #{@@headers.Subject}"
-body = "Please upload your public key.\n\nhttps://pgp.mit.edu/";
+body = "Dear #{@@headers.name},\n\n" +
+  "Can you please upload your public key?\n\n" + 
+  "http://apache.org/licenses/#submitting\n\n"; +
+  "Regards,\n\n"
 
 window.location = "mailto:#{encodeURIComponent(destination)}" +
   "?subject=#{encodeURIComponent(subject)}" +

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].


[whimsy] branch master updated: Use only symbols as hash keys

2016-04-06 Thread sebb
This is an automated email from the ASF dual-hosted git repository.

sebb pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  0a26a58   Use only symbols as hash keys
0a26a58 is described below

commit 0a26a5823111e27a095ecc8c0a27af8a723b3606
Author: Sebb 
AuthorDate: Wed Apr 6 18:32:35 2016 +0100

Use only symbols as hash keys
---
 www/status/monitor.rb| 53 ++--
 www/status/monitors/unit_test.rb |  4 +--
 2 files changed, 26 insertions(+), 31 deletions(-)

diff --git a/www/status/monitor.rb b/www/status/monitor.rb
index 86eba94..8be70f9 100644
--- a/www/status/monitor.rb
+++ b/www/status/monitor.rb
@@ -23,7 +23,7 @@ class Monitor
 
   # fetch previous status
   baseline = JSON.parse(file.read) rescue {}
-  baseline['data'] = {} unless baseline['data'].instance_of? Hash
+  baseline[:data] = {} unless baseline[:data].instance_of? Hash
 
   # If status was updated while waiting for the lock, use the new status
   if not File.exist?(status_file) or mtime != File.mtime(status_file)
@@ -39,7 +39,7 @@ class Monitor
 threads << Thread.new do
   begin
 # invoke method to determine current status
-previous = baseline['data'][method.to_s] || {mtime: Time.at(0)}
+previous = baseline[:data][method.to_s] || {mtime: Time.at(0)}
 status = Monitor.send(method, previous) || previous
 
 # convert non-hashes in proper statuses
@@ -64,7 +64,7 @@ class Monitor
   end
 
   # default mtime to now
-  status['mtime'] ||= Time.now if status.instance_of? Hash
+  status[:mtime] ||= Time.now if status.instance_of? Hash
 
   # store status in thread local storage
   Thread.current[:name] = method.to_s
@@ -106,62 +106,57 @@ class Monitor
   status = {data: status}
 end
 
-# convert symbols to strings
-status.keys.each do |key|
-  status[key.to_s] = status.delete(key) if key.instance_of? Symbol
-end
-
 # normalize data
-if status['data'].instance_of? Hash
+if status[:data].instance_of? Hash
   # recursively normalize the data structure
-  status['data'].values.each {|value| normalize(value)}
-elsif not status['data'] and not status['mtime']
+  status[:data].values.each {|value| normalize(value)}
+elsif not status[:data] and not status[:mtime]
   # default data
-  status['data'] = 'missing'
-  status['level'] ||= 'danger'
+  status[:data] = 'missing'
+  status[:level] ||= 'danger'
 end
 
 # normalize time
-if status['mtime'].instance_of? Time
-  status['mtime'] = status['mtime'].gmtime.iso8601
+if status[:mtime].instance_of? Time
+  status[:mtime] = status[:mtime].gmtime.iso8601
 end
 
 # normalize level (filling in title when this occurs)
-if status['level']
-  if not LEVELS.include? status['level']
-status['title'] ||= "invalid status: #{status['level'].inspect}"
-status['level'] = 'fatal'
+if status[:level]
+  if not LEVELS.include? status[:level]
+status[:title] ||= "invalid status: #{status[:level].inspect}"
+status[:level] = 'fatal'
   end
 else
-  if status['data'].instance_of? Hash
+  if status[:data].instance_of? Hash
 # find the values with the highest status level
-highest = status['data'].
-  group_by {|key, value| LEVELS.index(value['level']) || 9}.max ||
+highest = status[:data].
+  group_by {|key, value| LEVELS.index(value[:level]) || 9}.max ||
   [9, []]
 
 # adopt that level
-status['level'] = LEVELS[highest.first] || 'fatal'
+status[:level] = LEVELS[highest.first] || 'fatal'
 
 group = highest.last
 if group.length != 1
   # indicate the number of item with that status
-  status['title'] = "#{group.length} #{ISSUE_TYPE[status['level']]}"
+  status[:title] = "#{group.length} #{ISSUE_TYPE[status[:level]]}"
 
   if group.length <= 4
-status['title'] += ': ' + group.map(&:first).join(', ')
+status[:title] += ': ' + group.map(&:first).join(', ')
   end
 else
   # indicate the item with the problem
   key, value = group.first
-  if value['title']
-status['title'] ||= "#{key} #{value['title']}"
+  if value[:title]
+status[:title] ||= "#{key} #{value[:title]}"
   else
-status['title'] ||= "#{key} #{value['data'].inspect}"
+status[:title] ||= "#{key} #{value[:data].inspect}"
   end
 end
   else
 # default level
-status['level'] ||= 'success'
+status[:level] ||= 'success'
   end
 end
 
diff --git a/www/status/monitors/unit_test.rb b/www/status/moni

[whimsy] branch master updated: Fix monitoring to always use symbolic keys Check if public json log file has changed before copying Unit test improvement

2016-04-06 Thread sebb
This is an automated email from the ASF dual-hosted git repository.

sebb pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  c3cc337   Fix monitoring to always use symbolic keys Check if 
public json log file has changed before copying Unit test improvement
c3cc337 is described below

commit c3cc337b8222cc465361f3001b92b77f6d7cc146
Author: Sebb 
AuthorDate: Wed Apr 6 23:29:58 2016 +0100

Fix monitoring to always use symbolic keys
Check if public json log file has changed before copying
Unit test improvement
---
 www/status/monitor.rb  | 23 ++-
 www/status/monitors/public_json.rb | 23 +--
 www/status/monitors/system.rb  | 11 ++-
 www/status/monitors/unit_test.rb   | 17 ++---
 4 files changed, 51 insertions(+), 23 deletions(-)

diff --git a/www/status/monitor.rb b/www/status/monitor.rb
index 8be70f9..16d1ad0 100644
--- a/www/status/monitor.rb
+++ b/www/status/monitor.rb
@@ -1,8 +1,20 @@
 #
 # Overall monitor class is responsible for loading and running each
 # monitor in the `monitors` directory, collecting and normalizing the
-# results and outputting it as JSON.
+# results and outputting it as JSON for use in the GUI.
 #
+# The previous status is passed to the monitor on the next run so it can
+# determine when to take non-idempotent actions such as sending a message
+#
+# The monitors are called frequently, so the return status built up by
+# a monitor should be easily comparable with the input status. This means
+# using the same key and value formats (at least for monitors that need to
+# compare them).
+#
+# Although both string and symbolic keys can be used in hashes, the syntax
+# for symbolic keys is rather neater, so we use symbolic keys throughout.
+# This means that the JSON file is parsed into a hash using symbolic keys,
+# and any variables used as keys need to be converted to symbols.
 
 require 'json'
 require 'time'
@@ -21,8 +33,8 @@ class Monitor
   mtime = File.exist?(status_file) ? File.mtime(status_file) : Time.at(0)
   file.flock(File::LOCK_EX)
 
-  # fetch previous status
-  baseline = JSON.parse(file.read) rescue {}
+  # fetch previous status (using symbolic keys)
+  baseline = JSON.parse(file.read, {symbolize_names: true}) rescue {}
   baseline[:data] = {} unless baseline[:data].instance_of? Hash
 
   # If status was updated while waiting for the lock, use the new status
@@ -39,7 +51,7 @@ class Monitor
 threads << Thread.new do
   begin
 # invoke method to determine current status
-previous = baseline[:data][method.to_s] || {mtime: Time.at(0)}
+previous = baseline[:data][method.to_sym] || {mtime: Time.at(0)}
 status = Monitor.send(method, previous) || previous
 
 # convert non-hashes in proper statuses
@@ -116,7 +128,8 @@ class Monitor
   status[:level] ||= 'danger'
 end
 
-# normalize time
+# normalize time 
+# If the called monitor wants to compare status hashes it should store the 
correct format
 if status[:mtime].instance_of? Time
   status[:mtime] = status[:mtime].gmtime.iso8601
 end
diff --git a/www/status/monitors/public_json.rb 
b/www/status/monitors/public_json.rb
index 9a7be03..35076c8 100644
--- a/www/status/monitors/public_json.rb
+++ b/www/status/monitors/public_json.rb
@@ -3,6 +3,7 @@
 #
 
 require 'fileutils'
+require 'time'
 
 def Monitor.public_json(previous_status)
   danger_period = 86_400 # one day
@@ -18,14 +19,14 @@ def Monitor.public_json(previous_status)
   status = {}
 
   Dir[logs].each do |log|
-name = File.basename(log).sub('public-', '')
+name = File.basename(log).sub('public-', '').to_sym
 
 begin
   status[name] = {
 href: "../logs/#{File.basename(log)}",
-mtime: File.mtime(log)
+mtime: File.mtime(log).gmtime.iso8601, # to agree with normalise
+level: 'success' # to agree with normalise
   }
-
   contents = File.read(log, encoding: Encoding::UTF_8)
 
   # Ignore Wunderbar logging for normal messages (may occur multiple times)
@@ -81,13 +82,15 @@ def Monitor.public_json(previous_status)
   }
 end
 
-# Save a copy of the log
-# append the severity so can track more problems
-lvl = status[name][:level] 
-if lvl and lvl != 'info'
-  name = File.basename(log)
-  FileUtils.copy log, File.join(archive, name + '.' + lvl),
-preserve: true
+# Has there been a change since the last check?
+if status[name] != previous_status[:data][name]
+  lvl = status[name][:level] 
+  if lvl and lvl != 'info' # was there a problem?
+# Save a copy of the log; append the severity so can track more 
problems
+name = File.basename(log)
+# temporarily allow the date stamp to be updated so we can 

[whimsy] branch master updated: Just in case no previous data; also need to check success

2016-04-06 Thread sebb
This is an automated email from the ASF dual-hosted git repository.

sebb pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  f159daf   Just in case no previous data; also need to check success
f159daf is described below

commit f159daf43706679dae659024023d39a7bfbee171
Author: Sebb 
AuthorDate: Wed Apr 6 23:45:31 2016 +0100

Just in case no previous data; also need to check success
---
 www/status/monitors/public_json.rb | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/www/status/monitors/public_json.rb 
b/www/status/monitors/public_json.rb
index 35076c8..2401b95 100644
--- a/www/status/monitors/public_json.rb
+++ b/www/status/monitors/public_json.rb
@@ -83,9 +83,9 @@ def Monitor.public_json(previous_status)
 end
 
 # Has there been a change since the last check?
-if status[name] != previous_status[:data][name]
+if previous_status[:data] and status[name] != previous_status[:data][name]
   lvl = status[name][:level] 
-  if lvl and lvl != 'info' # was there a problem?
+  if lvl and lvl != 'info' and lvl != 'success' # was there a problem?
 # Save a copy of the log; append the severity so can track more 
problems
 name = File.basename(log)
 # temporarily allow the date stamp to be updated so we can see if the 
file is copied mulitple times

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].


[whimsy] branch master updated: Log messages to show where we might send an email (better to flood log than mailbox!)

2016-04-06 Thread sebb
This is an automated email from the ASF dual-hosted git repository.

sebb pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  d53d4d1   Log messages to show where we might send an email (better 
to flood log than mailbox!)
d53d4d1 is described below

commit d53d4d1826b0dbbf3e1b18a552baf54f44064ead
Author: Sebb 
AuthorDate: Thu Apr 7 00:17:30 2016 +0100

Log messages to show where we might send an email (better to flood log
than mailbox!)
---
 www/status/monitors/public_json.rb | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/www/status/monitors/public_json.rb 
b/www/status/monitors/public_json.rb
index 2401b95..ba0d6c5 100644
--- a/www/status/monitors/public_json.rb
+++ b/www/status/monitors/public_json.rb
@@ -85,11 +85,13 @@ def Monitor.public_json(previous_status)
 # Has there been a change since the last check?
 if previous_status[:data] and status[name] != previous_status[:data][name]
   lvl = status[name][:level] 
+  $stderr.puts "Status has changed for #{name} #{lvl}"
   if lvl and lvl != 'info' and lvl != 'success' # was there a problem?
 # Save a copy of the log; append the severity so can track more 
problems
 name = File.basename(log)
 # temporarily allow the date stamp to be updated so we can see if the 
file is copied mulitple times
 FileUtils.copy log, File.join(archive, name + '.' + lvl) #, preserve: 
true
+$stderr.puts "Would send e-mail for #{name} #{lvl}"
   end
 end
   end

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].


[whimsy] branch master updated: Unnecessary

2016-04-06 Thread sebb
This is an automated email from the ASF dual-hosted git repository.

sebb pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  ee3ae01   Unnecessary
ee3ae01 is described below

commit ee3ae01534b62398b0c2d077ff0142cc219a08b2
Author: Sebb 
AuthorDate: Thu Apr 7 00:34:06 2016 +0100

Unnecessary
---
 www/status/monitors/public_json.rb | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/www/status/monitors/public_json.rb 
b/www/status/monitors/public_json.rb
index ba0d6c5..bba798d 100644
--- a/www/status/monitors/public_json.rb
+++ b/www/status/monitors/public_json.rb
@@ -89,8 +89,7 @@ def Monitor.public_json(previous_status)
   if lvl and lvl != 'info' and lvl != 'success' # was there a problem?
 # Save a copy of the log; append the severity so can track more 
problems
 name = File.basename(log)
-# temporarily allow the date stamp to be updated so we can see if the 
file is copied mulitple times
-FileUtils.copy log, File.join(archive, name + '.' + lvl) #, preserve: 
true
+FileUtils.copy log, File.join(archive, name + '.' + lvl), preserve: 
true
 $stderr.puts "Would send e-mail for #{name} #{lvl}"
   end
 end

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].


[whimsy] branch master updated: Quieten; no longer needed

2016-04-06 Thread sebb
This is an automated email from the ASF dual-hosted git repository.

sebb pushed a commit to branch master
in repository https://git-dual.apache.org/repos/asf/whimsy.git

The following commit(s) were added to refs/heads/master by this push:
   new  bfffb67   Quieten; no longer needed
bfffb67 is described below

commit bfffb6726b40cd23ab0ef499b86f4687bfd10c69
Author: Sebb 
AuthorDate: Thu Apr 7 01:29:03 2016 +0100

Quieten; no longer needed
---
 www/status/monitors/public_json.rb | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/www/status/monitors/public_json.rb 
b/www/status/monitors/public_json.rb
index bba798d..36fd9fe 100644
--- a/www/status/monitors/public_json.rb
+++ b/www/status/monitors/public_json.rb
@@ -85,7 +85,7 @@ def Monitor.public_json(previous_status)
 # Has there been a change since the last check?
 if previous_status[:data] and status[name] != previous_status[:data][name]
   lvl = status[name][:level] 
-  $stderr.puts "Status has changed for #{name} #{lvl}"
+#  $stderr.puts "Status has changed for #{name} #{lvl}"
   if lvl and lvl != 'info' and lvl != 'success' # was there a problem?
 # Save a copy of the log; append the severity so can track more 
problems
 name = File.basename(log)

-- 
To stop receiving notification emails like this one, please contact
['"commits@whimsical.apache.org" '].