Module:Gerrit api test
Appearance
Documentation for this module may be created at Module:Gerrit api test/doc (Test cases • Test results)
local p = {}
local timezones = {
-- Add timezone offsets here!
Z = 0,
UTC = 0,
PST = -8,
PDT = -7,
SF = 'America/Los_Angeles',
DE = 'Europe/Berlin',
}
local timezones2 = {
SF = 'America/Los_Angeles',
DE = 'Europe/Berlin',
}
function getSanFranciscoTimezone( time )
-- mw.getContentLanguage():formatDate() will handle input with tzdata
-- timezones, outputting the corresponding time in UTC. So we pass it input
-- that is manually offset for PST and PDT and see which one matches UTC.
local utc = os.date( '!%FT%TZ', time )
local pst = mw.getContentLanguage():formatDate( 'Y-m-d\\TH:i:s\\Z', os.date( '!%FT%T America/Los_Angeles', time + timezones.PST * 3600 ) )
local pdt = mw.getContentLanguage():formatDate( 'Y-m-d\\TH:i:s\\Z', os.date( '!%FT%T America/Los_Angeles', time + timezones.PDT * 3600 ) )
if utc == pst then
return 'PST'
elseif utc == pdt then
return 'PDT'
else
mw.logObject( { UTC = utc, PST = pst, PDT = pdt }, 'Cannot determine SF time' )
return 'PST'
end
end
function trim( str )
-- Trims a string because wikitech apparently doesn't have this library...
str = string.gsub( str, "%s+$", "" )
str = string.gsub( str, "^%s+", "" )
return str
end
function p.row( frame )
-- Produces a raw row to be reconsumed by this script for sorting
-- Expects:
--- when, string, like YYYY-MM-DD HH:mm XXX where XXX is a valid timezone listed in timezones
--- length, number, of hours the deploy will take
--- window, string, what deployment window this is (e.g. SWAT, parsoid, MediaWiki)
--- who, string, who is performing the deploy
--- what, string, what will be deployed
--
-- Outputs: UTC Timestamp,Length,Who,What
--- commas in strings are replaced with ,
local when = frame.args['when']
local length = ( tonumber( frame.args['length'] ) or 2 ) * 60 * 60
local window = frame.args['window'] or "N/A"
local who = frame.args['who'] or "Anonymous Cowards (must provide 'who=')"
local what = frame.args['what'] or "Nothing? Then why is this an entry!? (must provide 'what=')"
who = string.gsub( who, ",", "," )
what = string.gsub( what, ",", "," )
if when == nil then
utc_time = 0
what = "No time given (must provide 'when' and 'tz', e.g.: 'when=YYYY-MM-DD HH:mm XXX'"
else
year, month, day, hour, minute, tz = string.match( when, '^(%d+)-(%d+)-(%d+) (%d+):(%d+) ([A-Z]+)$' )
tz = timezones[tz]
if tz == nil then
utc_time = 0
what = "Unknown timezone in 'when' string! -- add it to the module :)"
elseif type( tz ) == 'string' then
local when2 = string.format( '%d-%d-%dT%d:%d:00 %s',
year or 1980,
month or 1,
day or 1,
hour or 1,
minute or 1,
tz
)
utc_time = mw.getContentLanguage():formatDate( 'U', when2 )
else
ts = os.time({
year = year or 1980,
month = month or 1,
day = day or 1,
hour = hour or 1,
min = minute or 1
})
utc_time = ts - ( tz * 60 * 60 )
end
end
return string.format( "%s,%s,%s,%s,%s", utc_time, length, window, who, what )
end
function p.makeGerritSearchLink(utc)
local dow = os.date('%u', utc)
local hour = os.date('%H', utc)
local swatWindow
if hour == '23' then
swatWindow = 'evening'
elseif hour == '18' and dow ~= '3' then
swatWindow = 'morning'
elseif hour == '16' and dow == '3' then
swatWindow = 'morning'
elseif hour == '11' then
swatWindow = 'eu'
else
swatWindow = hour
end
local swatTag = string.format('swat-%s-%s', os.date("%Y-%m-%d", utc), swatWindow)
return string.format("'''Gerrit hashtag''': [https://gerrit.wikimedia.org/r/#/q/hashtag:%s %s]", swatTag, swatTag)
end
function p.formatTable( frame )
-- Formats a bunch of rows from p.row()
local rows = {}
local row
local count = 1
local retval = {}
local sflocal
local sfdatestr
local showdate = not ( frame.args['hidedate'] == 'true' )
local tzoffset = 0
local cutcday
local sftz = "No data"
-- Load and sort the arguments
row = frame.args[count]
while not ( row == nil ) do
utc, length, window, who, what = string.match( row, '^(.*),(.*),(.*),(.*),(.*)$' )
utc = tonumber( trim ( utc ) )
length = tonumber( trim( length ) )
who = trim( who )
what = trim( what )
table.insert( rows, { utc=utc, length=length, window=window, who=who, what=what } )
count = count + 1
row = frame.args[count]
end
table.sort( rows, function( a, b ) return a.utc < b.utc end )
-- For each entry create the final row
for count = 1, #rows do
local datestr
utc = rows[count].utc
length = rows[count].length
window = rows[count].window
who = rows[count].who
what = rows[count].what
if ( cutcday ~= os.date( '%x', utc ) ) then
-- Create a new date header in the table
table.insert( retval, "|-\n| colspan='4' class='deploycal-dayrow' | \n==== " .. os.date( "!%A, %B %d", utc ) .. " ====" )
cutcday = os.date( '%x', utc )
end
sftz = getSanFranciscoTimezone( utc )
tzoffset = timezones[sftz]
sflocal = utc + ( tzoffset * 60 * 60 )
-- Determine if the SF day is different from the UTC day
if os.date( "!%A", utc ) ~= os.date( "!%A", sflocal ) then
sfdatestr = os.date( "!<small>(%a)</small> ", sflocal )
else
sfdatestr = ""
end
-- if it's swat, but not puppet swat
if string.find(window, "Puppet SWAT") == nil and string.find( window, "SWAT" ) ~= nil then
what = string.format("%s\n%s", what, p.makeGerritSearchLink(utc))
end
table.insert( retval, string.format( [=[ |- id="deploycal-item-%s" class="deploycal-item"
| <span class="deploycal-time-utc">%s–%s UTC [[#deploycal-item-%s|#]]</span> <br/> <span class="deploycal-time-sf">%s %s–%s %s</span>
| <span class="deploycal-window">%s</span>
| %s
| %s
]=],
os.date( "!%Y%m%dT%H%M", utc ),
'<time class="deploycal-starttime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+00:00", utc ) .. '">' ..
os.date( "!%H:%M", utc ) .. '</time>',
'<time class="deploycal-endtime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+00:00", utc + length ) .. '">' ..
os.date( "!%H:%M", utc + length ) .. "</time>",
os.date( "!%Y%m%dT%H%M", utc ),
sfdatestr,
'<time class="deploycal-starttime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+" .. tzoffset .. ":00", sflocal ) .. '">' ..
os.date( "!%H:%M", sflocal ) .. "</time>",
'<time class="deploycal-endtime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+" .. tzoffset .. ":00", sflocal + length ) .. '">' ..
os.date( "!%H:%M", sflocal + length ) .. "</time>",
sftz,
window,
who,
what
))
end
return string.format( [[
{| class='wikitable deploycal'
!Time
!Component
!Deployer
!Changes
]], sftz ) .. table.concat( retval, "\n" ) .. "\n|}"
end
-- Re-usable version for the timestamp anchor logic in 'row' and 'formatTable'.
-- Used on [[User:Krinkle/Deployments sandbox]].
function p.anchor( frame )
local start = frame.args['start']
if start == nil or start == '' then
return ""
end
year, month, day, hour, minute, tz_raw = string.match( start, '^(%d+)-(%d+)-(%d+) (%d+):(%d+) ([A-Z]+)$' )
tz = timezones2[tz_raw] or tz_raw
local formatted = string.format( '%d-%d-%dT%d:%d:00 %s',
year or 1980,
month or 0,
day or 0,
hour or 0,
minute or 42,
tz
)
utc = tonumber( mw.getContentLanguage():formatDate( 'U', formatted ) )
return string.format( 'id="deploycal-item-%s"', os.date( "!%Y%m%dT%H%M", utc ) )
end
-- Re-usable version for the date fomatting logic in 'row' and 'formatTable'.
-- Used on [[User:Krinkle/Deployments sandbox]].
function p.when( frame )
local start = frame.args['start']
local seconds = ( tonumber( frame.args['hours'] ) or 2 ) * 60 * 60
if start == nil or start == '' then
return "No time given"
end
year, month, day, hour, minute, tz_raw = string.match( start, '^(%d+)-(%d+)-(%d+) (%d+):(%d+) ([A-Z]+)$' )
tz = timezones2[tz_raw] or tz_raw
local formatted = string.format( '%d-%d-%dT%d:%d:00 %s',
year or 1980,
month or 0,
day or 0,
hour or 0,
minute or 42,
tz
)
utc = tonumber( mw.getContentLanguage():formatDate( 'U', formatted ) )
sftz = getSanFranciscoTimezone( utc )
tzoffset = timezones[sftz]
sflocal = utc + ( tzoffset * 60 * 60 )
-- Determine if the SF day is different from the UTC day
if os.date( "!%A", utc ) ~= os.date( "!%A", sflocal ) then
sfdatestr = os.date( "!<small>(%a)</small> ", sflocal )
else
sfdatestr = ""
end
return string.format( '<span class="deploycal-time-utc">%s–%s UTC [[#deploycal-item-%s|#]]</span>' ..
' <br/> ' ..
'<span class="deploycal-time-sf">%s %s–%s %s</span>',
'<time class="deploycal-starttime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+00:00", utc ) .. '">' ..
os.date( "!%H:%M", utc ) .. '</time>',
'<time class="deploycal-endtime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+00:00", utc + seconds ) .. '">' ..
os.date( "!%H:%M", utc + seconds ) .. "</time>",
os.date( "!%Y%m%dT%H%M", utc ),
sfdatestr,
'<time class="deploycal-starttime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+" .. tzoffset .. ":00", sflocal ) .. '">' ..
os.date( "!%H:%M", sflocal ) .. "</time>",
'<time class="deploycal-endtime" datetime="' .. os.date( "!%Y-%m-%dT%H:%M+" .. tzoffset .. ":00", sflocal + seconds ) .. '">' ..
os.date( "!%H:%M", sflocal + seconds ) .. "</time>",
sftz
)
end
function p.header( frame )
-- In my young and dumb days, this created a header for formatTable.
-- We still need it because the archive page calls it (though it no longer needs to)
end
function p.footer( frame )
-- In my young and dumb days, this created a footer for formatTable.
-- We still need it because the archive page calls it (though it no longer needs to)
end
return p