function reviewDaemon {param([switch]$resetReviewCounter,[switch]$justProcessReviews,[switch]$verbose) $servercheck = p4get-server if ($servercheck.pingsuccess.equals($false)) { write-error "Server check failed - sign into p4 using p4ps1 method" break } if (!$env:depotsxml) { write-error "Could not locate depots.xml configuration file." break } $static = ([xml](gc $env:depotsxml)).perforce.reviewService #get a bunch of static declarations from config file. This includes css config for formatting mail messages $static.css > ($env:temp + "\reviewDaemon.css") #squirt out css template from config to a temp location for html converter $verbosePrefs = $verbosePreference #store the original console verbosity preference $verbosePreference = "continue" #set it to continue for messaging. $counters = p4get-counters #get the counters for the logged in server $i = 1 #counter used for the progress bars $reviewObjects = @() #array for each review message that will be sent $counterStatus = $null #text returned from p4 when updating the review counter $reviewMessage = $null #a property for creating a review message $changeObject = $null #the object containing the changelist selected for a review message $reviewSubscribers = $null #the object containing all the subscribers for a particular review. $changeList = $null #the starting changelist number for processing set to null for state testing $changeList = [int]$counters.review #try to load the counters of the last review into changelist $mailSubject = $null #subject for sending mail if (!$counters.review) #if the counter isn't found, then counters aren't configured here. Exit. { write-error "Review counter not found" break } if (($counters.review -1) -eq $counters.change) { write-verbose ("`r`n`r`n********************************************************"` + ("`r`nReview counter at top of changes. [" + $counters.review + "] No reviews to process.")` + "`r`n********************************************************") return } if ($counters.review -gt $counters.change) { write-warning ("Review counter state is inconsistent with change counter.`r`n`r`nChange [" + $counters.change + "]" + "`r`nReview [" + $counters.review + "]`r`nResetting review counter and exiting.") p4 counter review $counters.change return } if ($static.maxChangelistsProcessed -le 0) { write-error "maxChangelistsProcessed must be an integer larger than zero" break } if ($static.maxReviewsPerRun -le 0) { write-error "maxReviewsPerRun must be an integer larger than zero" break } else #if a counter is found, proceed. { write-progress -id 1 -activity ("Powershell Perforce Review Daemon - Connected to " + $servercheck.server + ":" + $servercheck.port) if ($resetReviewCounter) #if the reset review counter switch invoked, set it to be the same as the change counter. This sets the pointer for reviews from the point the reset was invoked. { p4 counter review $counters.change #set review counter to the change counter. } do { $counterChangeDelta = ($counters.change - $counters.review) #make sure to set the clamp so if counters.change == counters.review, not do anything zzz if ($counterChangeDelta -le 0) { write-progress -id 50 -activity ("Working on [" + $i + "] of [" + $counterChangeDelta + "] changelist(s).") -status ("Changelist: [" + $changeList + "] " + "Until current: [" + ($counterChangeDelta - $i) + "]") -percentcomplete 100 } else { write-progress -id 50 -activity ("Working on [" + $i + "] of [" + $counterChangeDelta + "] changelist(s).") -status ("Changelist: [" + $changeList + "] " + "Until current: [" + ($counterChangeDelta - $i) + "]") -percentcomplete ($i/$counterChangeDelta*100) } $command = "reviews -c " + $changeList $reviewcheck = p4get $command if ($reviewcheck) { if ($reviewObjects.count -eq 0) #this progress report isn't entirely accurate, as being inside this loop means a review was found. However, there is a good likelyhood that there were previous changes that did not have reviews, and the "no review notifications" message is accurate. { write-progress -id 10 -activity ("No review notifications found.") -status ("Processed " + $reviewObjects.count + " review(s) out of a maximum of " + $static.maxReviewsPerRun) -percentcomplete ($reviewObjects.count/($static.maxReviewsPerRun)*100) } if ($reviewObjects.count -gt 0) #this progress report isn't entirely accurate, as being inside this loop means a review was found. However, there is a good likelyhood that there were previous changes that did not have reviews, and the "no review notifications" message is accurate. { write-progress -id 10 -activity ("Looking for more review notification messages.") -status ("Processed " + $reviewObjects.count + " review(s) out of a maximum of " + $static.maxReviewsPerRun) -percentcomplete ($reviewObjects.count/($static.maxReviewsPerRun)*100) } $changeObject = p4get-changedescription $changeList -depotFileLimit 50 #sticking this outside the foreach user loop so we don't query the perforce server excessively. stop at 50 file objects if there are more than that. foreach ($subscriber in $reviewcheck.email) { $reviewMessage = new-object pscustomobject #object holding the parent message container $reviewMessageHeader = new-object pscustomobject #object that contains the header #there is no $reviewMessageText because it needs to be processed explicitly for html content to render right. $reviewMessageFiles = new-object pscustomobject #object containing the file list ## header objects # add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name Subscriber -value $subscriber add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name Changelist -value $changeObject.change add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name Date -value $changeObject.time add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name Submitter-User -value $changeObject.user add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name Submitter-Email -value (p4get-user $changeObject.user).email add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name Client -value $changeObject.client if (($changeObject.desc | out-string).length -le 127) { add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name TruncatedDescription -value ($changeObject.desc | out-string | %{$_ -replace "`t|`n|`r",""}) } else { add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name TruncatedDescription -value ($changeObject.desc | out-string | %{$_ -replace "`t|`n|`r",""}).Substring(0,127 ) } if ($changeObject.incompleteFileList -eq $true) { add-member -inputobject $reviewMessageHeader -membertype NoteProperty -name incompleteFileList -value $changeObject.incompleteFileList } $reviewMessage | add-member -membertype NoteProperty -name MessageHeader -value $reviewMessageHeader #add header objects to message # ## end header object ## description object. # $descriptionText = ("`r`n`r`n`r`n`r`n
Description
" + (($changeObject.desc | out-string)| %{$_ -replace '<','<'}| %{$_ -replace '>','>'}| %{$_ -replace '(?m)\n', "`r`n
"})+"
") #description object #make a table header. #squirt out the raw change description text as a big string. #replace all the lessthan with html friendly text #replace all the greaterthan with html friendly text #replace all the newlines with
#close the table $reviewMessage | add-member -membertype NoteProperty -name MessageDescription -value $descriptionText #add description object to message # ## end description object ## files object # $reviewMessage | add-member -membertype NoteProperty -name MessageFiles -value ($changeObject.depotfile) #add files description object to message # ## end files object $reviewObjects += $reviewMessage #add the object onto the array of review messages to be sent out. } } $i++ $changeList++ } until (([int]$reviewObjects.count -ge [int]$static.maxReviewsPerRun) -or ([int]$i -gt [int]$static.maxChangelistsProcessed) -or ([int]$changelist -ge [int]$counters.change)) #cast all as int just in case something gets assigned a wierd text string and never evaluates. #until (number of reviews foreach ($object in $reviewObjects) { if ($justProcessReviews) #if the switch justprocessreviews is set, return the contents as an object and do not send out emails. { @{"header" = $object.MessageHeader;"description" = $object.MessageDescription;"files" = $object.MessageFiles} write-verbose ("Setting review counter to " + $object.MessageHeader.Changelist) #inform that the review counter is being updated after a successful mail send p4 counter review $object.MessageHeader.Changelist 2>$counterStatus | out-null } else { $mailSubject = ("[Perforce Review Notification] " + $servercheck.server + ":" + $servercheck.port + " - " + $object.MessageHeader.TruncatedDescription + " - #" + $object.MessageHeader.changelist) $mailFrom = ($servercheck.server + "ReviewDaemon@" + $static.mailDomain) try { #generate the style css $style = "" #generate the body $body = ConvertTo-HTML -body $style -inputobject $object.MessageHeader -property Changelist,Submitter-User,Submitter-Email,Date,Client $body += "
" $body += $object.MessageDescription $body += "
" $body += $object.MessageFiles | ConvertTo-HTML -property action,depotfile,rev,filesize,type #send the message Send-MailMessage -to $object.MessageHeader.Subscriber -subject $mailSubject -from $mailFrom -body ($body | out-string) -smtpserver $static.mailSMTPServer -priority $static.mailPriority -BodyAsHtml if ($verbose) { @{"header" = $object.MessageHeader;"description" = $object.MessageDescription;"files" = $object.MessageFiles} } } catch { write-error $error[0] write-error ("Notification NOT sent. No further messages will be processed, and the review counter will not be updated.") break } write-verbose ("Notification sent. Setting review counter to " + $object.MessageHeader.Changelist) #inform that the review counter is being updated after a successful mail send p4 counter review $object.MessageHeader.Changelist 2>$counterStatus | out-null } } p4 counter review $changeList 2>$counterStatus | out-null write-verbose ("`r`n`r`n*******************************************************"` + "`r`nReview notifications found : " + $reviewObjects.count ` + "`r`nLast review changelist : " + $changeList ` + "`r`nSetting review counter for next session to : " + $changeList ` + "`r`nHighest changelist number : " + $counters.change ` + "`r`n*******************************************************") } $verbosePreference = $verbosePrefs #return verbosity preferences to the configured. }