# # Copyright 2005 Perforce Software. All rights reserved. # require "P4Data.rb" require "P4Form.rb" require "P4Valid.rb" require "P4Jobs.rb" require "P4Mail.rb" def notify_people(notify, job, type, n_form, body) # # Notifications # if n_form.fields[P4OWNEDBYFIELD] != nil then notify["to"] << n_form.fields[P4OWNEDBYFIELD] end if n_form.fields[P4INTERESTEDINFIELD] != nil then notify["cc"] << extract_set(n_form.fields[P4INTERESTEDINFIELD]) end notify["cc"] << product_watchers(P4INTERESTED, n_form.fields[P4PRODUCTFIELD]) notify["cc"].flatten! notify["cc"].compact! notify["cc"].sort! notify["cc"].uniq! notify["to"].flatten! notify["to"].compact! notify["to"].sort! notify["to"].uniq! if notify["to"].length > 0 || notify["cc"].length > 0 then dlist = n_form.fields[P4DESCRIPTIONFIELD].split(/[ \t]*\n[ \t\n]*/) description = "" if dlist[0] == nil || dlist[0].strip == "" then if dlist[1] == nil then description = "" else description = dlist[1].strip end else description = dlist[0].strip end msg = P4Mail.new msg.from = P4ADMINEMAIL msg.to_list << notify["to"] msg.to_list.flatten! msg.cc_list << notify["cc"] msg.cc_list.flatten! msg.subject = sprintf("Job %s: %s - %s", type, job, description) msg.body = body.join("\n") msg.send() end end # # Logic for processing of duplicates # Return "" for accepting job or "problem desc" for rejecting job # # Duplicate Handling: # - Update DuplicateOf job in the following ways: # Add current jobid to DuplicateJobs # For each field in P4DUPAPPEND, append dup's field values # - Generate a discrepency report if needed # def dup_job(u, logfile, myjobid, dupjobid, n_form, chain) rejected = "" d_form = P4Form.new(`#{P4_BIN} -u #{P4USER} -p #{P4PORT} job -o #{dupjobid}`.split("\n")) # # Update DuplicateJob field # curdups = extract_set(d_form.fields[P4DUPLICATEJOBSFIELD]) logfile.printf("Adding to DuplicateJobs [%s]: [%s]\n", ##DEBUG curdups.join(", "), myjobid) ##DEBUG if curdups.include?(myjobid) then logfile.printf("DuplicateJobs already contains: [%s]\n", ##DEBUG myjobid) ##DEBUG return rejected end curdups << myjobid curdups.uniq! curdups.sort! if P4SETS[P4DUPLICATEJOBSFIELD] == "1" then d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join(" ") else d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join("\n\t") end # # COPY/CUT Fields # (P4DUPCOPY+P4DUPCUT).each do |field| if n_form.fields.keys.include?(field) then newval = "" if d_form.fields.keys.include?(field) then if P4HISTORY[field] != "text" then newval = sprintf("%s %s", d_form.fields[field], n_form.fields[field]) else newval = sprintf("%s\n\t%s", d_form.fields[field], n_form.fields[field]) end else newval = n_form.fields[field] end if P4SETS.keys.include?(field) then if P4SETS[field] == "1" then d_form.fields[field] = extract_set(newval).sort.join(" ") else d_form.fields[field] = extract_set(newval).sort.join("\n\t") end else d_form.fields[field] = newval end end end # # Save Job # p4proc = IO.popen("p4 -u #{u} job -i", "w+") # Force user to be 'u' logfile.printf("Updating job:\n") ##DEBUG d_form.print(logfile) ##DEBUG d_form.print(p4proc) p4proc.printf("EJPUserID: %s\n", u) # Tag as EJP update and save UserID p4proc.printf("EJPChain: %s %s\n", myjobid, chain) # Add cur to chain p4proc.close_write saved = false p4proc.each do |line| logfile.print line ##DEBUG if line =~ /Job #{dupjobid} saved/ then saved = true end end p4proc.close_read if !saved then rejected = "Unable to update specified DuplicateOf job" end return rejected end def undup_job(u, logfile, myjobid, dupjobid, n_form, chain) rejected = "" d_form = P4Form.new(`#{P4_BIN} -u #{P4USER} -p #{P4PORT} job -o #{dupjobid}`.split("\n")) # # Update DuplicateJob field # curdups = extract_set(d_form.fields[P4DUPLICATEJOBSFIELD]) logfile.printf("Removing from DuplicateJob: [%s] with [%s]\n", ##DEBUG curdups.join(", "), myjobid) ##DEBUG curdups.delete(myjobid) curdups.uniq! curdups.sort! if P4SETS[P4DUPLICATEJOBSFIELD] == "1" then d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join(" ") else d_form.fields[P4DUPLICATEJOBSFIELD] = curdups.join("\n\t") end # # Save Job # p4proc = IO.popen("p4 -u #{u} job -i", "w+") # Force user to be 'u' logfile.printf("Updating job:\n") ##DEBUG d_form.print(logfile) ##DEBUG d_form.print(p4proc) p4proc.printf("EJPUserID: %s\n", u) # Tag as EJP update and save UserID p4proc.printf("EJPChain: %s %s\n", myjobid, chain) # Add cur to chain p4proc.close_write saved = false p4proc.each do |line| logfile.print line ##DEBUG if line =~ /Job #{dupjobid} saved/ then saved = true end end p4proc.close_read if !saved then rejected = "Unable to update specified DuplicateOf job" end return rejected end # # Logic for processing of RelatedJobs # Return "" for accepting job or "problem desc" for rejecting job # # RelatedJobs Handling: maintain cross-reference btw jobs # def related_job(u, logfile, add_flag, myjobid, reljobid, chain) rejected = "" if myjobid == reljobid then return rejected end r_form = P4Form.new(`#{P4_BIN} -u #{P4USER} -p #{P4PORT} job -o #{reljobid}`.split("\n")) related_jobs = extract_set(r_form.fields[P4RELATEDJOBSFIELD]) logfile.printf("RelatedJobs(Pre)[%s]\n", related_jobs.join("|")) ##DEBUG if add_flag then related_jobs << myjobid else related_jobs.delete(myjobid) end logfile.printf("RelatedJobs(Post)[%s]\n", related_jobs.join("|")) ##DEBUG r_form.fields[P4RELATEDJOBSFIELD] = related_jobs.join(", ") p4proc = IO.popen("p4 -u #{u} job -i", "w+") # Force user to be 'u' logfile.printf("Updating job:\n") ##DEBUG r_form.print(logfile) ##DEBUG r_form.print(p4proc) p4proc.printf("EJPUserID: %s\n", u) # Tag as EJP update and save UserID p4proc.printf("EJPChain: %s %s\n", myjobid, chain) # Add cur to chain p4proc.close_write saved = false p4proc.each do |line| logfile.print line ##DEBUG if line =~ /Job #{reljobid} saved/ then saved = true end end p4proc.close_read if !saved then rejected = "Unable to update specified RelatedJob job" end return rejected end # # Logic for processing of job changes # Return "" for accepting job or "problem desc" for rejecting job # # Update n_form with any changes to be made to job # def job_changed(ts, u, logfile, n_form, o_form, changed, added, deleted) notify = { "to" => [], "cc" => [] } rejected = "" myjobid = n_form.fields[P4JOBFIELD].strip if (changed.include?(P4DUPLICATEOFFIELD) || added.include?(P4DUPLICATEOFFIELD)) && n_form.fields[P4STATUSFIELD].strip != "duplicate" then rejected = "DuplicateOf cannot be defined for non-duplicate jobs" elsif (n_form.fields[P4STATUSFIELD].strip == "duplicate" && n_form.fields[P4DUPLICATEOFFIELD] == nil) then rejected = "Duplicate jobs must have DuplicateOf defined\n" elsif changed.include?(P4DUPLICATEOFFIELD) then rejected = "DuplicateOf cannot be changed, change state and delete field" end duped = false if rejected == "" && changed.include?(P4STATUSFIELD) then if n_form.fields[P4STATUSFIELD].strip == "duplicate" then # # Duplicate Handling: # - Check that DupliateOf is defined, else error # dupjobid = n_form.fields[P4DUPLICATEOFFIELD] if dupjobid == nil then rejected = "Duplicate jobs must have DuplicateOf defined\n" elsif ( dupjobid == myjobid ) rejected = "Duplicate jobs may not be a duplicate of themselves\n" else rejected = dup_job(u, logfile, myjobid, dupjobid.strip, n_form, n_form.chain) duped = true if !changed.include?(P4OWNEDBYFIELD) then # Since the owner wasn't changed, update accordingly newowner = state_owner(P4FLOW, n_form.fields, P4STATUSFIELD, P4PRODUCTFIELD) if newowner != "" && newowner != n_form.fields[P4OWNEDBYFIELD] then if n_form.fields[P4OWNEDBYFIELD] != nil then changed << P4OWNEDBYFIELD else added << P4OWNEDBYFIELD end n_form.fields[P4OWNEDBYFIELD] = newowner end end end elsif n_form.fields.keys.include?(P4DUPLICATEOFFIELD) then rejected = "DuplicateOf cannot be defined for non-duplicate jobs" else # SOME OTHER STATUS CHANGE TO BE HANDLED if o_form.fields[P4STATUSFIELD].strip == "duplicate" then dupjobid = o_form.fields[P4DUPLICATEOFFIELD] rejected = undup_job(u, logfile, myjobid, dupjobid.strip, n_form, n_form.chain) end if n_form.fields[P4STATUSFIELD].strip == "closed" then # Save who closed the job n_form.fields[P4CLOSEDBYFIELD] = u if o_form.fields[P4CLOSEDBYFIELD] != nil then changed << P4CLOSEDBYFIELD else added << P4CLOSEDBYFIELD end end if !changed.include?(P4OWNEDBYFIELD) then # Since the owner wasn't changed, update accordingly newowner = "" if n_form.fields[P4STATUSFIELD].strip == "closed" && n_form.fields["ClosedOwner"] != nil then newowner = n_form.fields["ClosedOwner"] else newowner = state_owner(P4FLOW, n_form.fields, P4STATUSFIELD, P4PRODUCTFIELD) end if newowner != "" && newowner != n_form.fields[P4OWNEDBYFIELD] then if n_form.fields[P4OWNEDBYFIELD] != nil then changed << P4OWNEDBYFIELD else added << P4OWNEDBYFIELD end n_form.fields[P4OWNEDBYFIELD] = newowner end end end end # # Handle RelatedJobs field, but only for the first job # if rejected == "" && (changed.include?(P4RELATEDJOBSFIELD) || added.include?(P4RELATEDJOBSFIELD) || deleted.include?(P4RELATEDJOBSFIELD)) then n_jobs = extract_set(n_form.fields[P4RELATEDJOBSFIELD]) o_jobs = extract_set(o_form.fields[P4RELATEDJOBSFIELD]) del_jobs = o_jobs - n_jobs del_jobs.each do |job| if !n_form.chain.include?(job) then rejected = related_job(u, logfile, false, myjobid, job, n_form.chain) end if rejected != "" then break end end if rejected == "" then add_jobs = n_jobs - o_jobs add_jobs.each do |job| if !n_form.chain.include?(job) then rejected = related_job(u, logfile, true, myjobid, job, n_form.chain) end if rejected != "" then break end end end end # # Add History Info # if rejected == "" then moved = [] if duped then P4DUPCUT.each do |field| if n_form.fields.keys.include?(field) then moved << field end end end append_history(ts, u, logfile, n_form, o_form, changed, added, deleted, moved) moved.each do |field| n_form.fields[field] = "" end if changed.include?(P4OWNEDBYFIELD) || deleted.include?(P4OWNEDBYFIELD) then notify["to"] << o_form.fields[P4OWNEDBYFIELD] end if changed.include?(P4STATUSFIELD) && n_form.fields[P4STATUSFIELD] =~ /(closed|punted)/ then notify["to"] << n_form.fields[P4REPORTEDBYFIELD] end if changed.include?(P4REPORTEDBYFIELD) then notify["to"] << o_form.fields[P4REPORTEDBYFIELD] end if o_form.fields[P4INTERESTEDINFIELD] != nil then # May be duplicates and such but they will be dropped later on notify["cc"] << extract_set(o_form.fields[P4INTERESTEDINFIELD]) end history_chunks = n_form.fields[P4HISTORYFIELD].split(/[ \t]*\n/) body = [] history_chunks.each do |line| if line == "" then break; end body << line[1..-1] end notify_people(notify, myjobid, "Updated", n_form, body) end return rejected end # # Logic for processing of new jobs # Return "" for accepting job or "problem desc" for rejecting job # # Update n_form with any changes to be made to job # def job_added(ts, u, logfile, n_form) logfile.printf("job_added(%s %s)\n", ts, u) ##DEBUG logfile.printf("n_form:\n") ##DEBUG n_form.print(logfile) ##DEBUG if n_form.fields[P4STATUSFIELD] == nil then return "Status must be specified" end if n_form.fields[P4STATUSFIELD].strip == "duplicate" then return "Status cannot be initialized as duplicate" end if n_form.fields[P4STATUSFIELD].strip == "closed" then return "Status cannot be initialized as closed" end if n_form.fields.keys.include?(P4DUPLICATEOFFIELD) then return "DuplicateOf cannot be defined for non-duplicate jobs" end if !n_form.fields.keys.include?(P4OWNEDBYFIELD) then # Since the owner has not been set, update accordingly newowner = state_owner(P4FLOW, n_form.fields, P4STATUSFIELD, P4PRODUCTFIELD) logfile.printf("RevisedOwner: %s\n", newowner) ##DEBUG if newowner != "" then n_form.fields[P4OWNEDBYFIELD] = newowner end end n_form.fields[P4HISTORYFIELD] = sprintf("%s user %s created job", ts, u) return "" end