autointeg.rb #1

  • //
  • guest/
  • tony_smith/
  • perforce/
  • P4Rubylib/
  • triggers/
  • autointeg.rb
  • View
  • Commits
  • Open Download .zip Download (6 KB)
#!/usr/bin/ruby
#--
#-------------------------------------------------------------------------------
#++
#== Introduction
#
#     This script keeps a slave branch synchronised with a master branch based
#     on the contents of a branch view. This could mean a single file, or an
#     entire tree - it's up to you. There are two ways to limit the scope of
#     the script:
#
#	1. Use a limited mapping in the trigger specification
#	2. Use a limited mapping in the branch specification
#
#     As you can see, the methods are similar.
#
#== Requirements
#  
#     Ruby
#  	http://www.ruby-lang.org
#  
#     P4Ruby
#  	http://public.perforce.com/guest/tony_smith/perforce/API/Ruby/index.html
#  
#     Rubymail
#  	http://raa.ruby-lang.org/project/rubymail/
#  
#== Trigger Specification
#  
#     An suitable trigger specification might look like this:
#  
#     autointeg commit //depot/master/... "t/autointeg.rb -b ms -c %changelist%"
#  
#     This would cause all changes to files under //depot/master/... that are
#     mapped by the branch specification 'ms' (master-slave) to be propagated
#     immediately to the slave copy.
#  
#--
#-------------------------------------------------------------------------------
#++

require "P4"
require "getoptlong"
require "net/smtp"
require "rmail/message"

#--
#-------------------------------------------------------------------------------
# CONFIGURATION SECTION
#-------------------------------------------------------------------------------
#++

# Email address of the Perforce administrator - notifications will be 
# sent to this user if EMAIL_REPORTS is true
ADMIN_EMAIL	= 	"perforce@localhost"

# If true, reports of the integrations performed will be emailed to the
# address above. Default: false.
EMAIL_REPORTS	= 	false

# The name of your SMTP server. The script uses SMTP to send notifications
# by email if EMAIL_REPORTS is true. 
SMTP_SERVER	= 	"localhost"

# The email address messages from this script should appear to come from
FROM_ADDRESS	= 	"perforce@localhost"

# The subject line for the messages
MSG_SUBJECT	=	"Automatic integration report"

# Causes the text of the email that would be sent to be dumped to stderr -
# which in the case of a trigger means it goes to the client.
DEBUG		= 	false

#
# Perforce environment. Unless these values are explicitly specified
# here, all the Perforce settings will be taken from the calling environment.
# This means you can use it with P4CONFIG files, and with 'p4 login' 
# tickets if you want to. If you use tickets, make sure the script user is
# in a group with a really, really long ticket timeout.

P4USER		= nil
P4PORT		= nil
P4CLIENT	= nil
P4PASSWD	= nil

#--
#-------------------------------------------------------------------------------
# END OF CONFIGURATION SECTION
#-------------------------------------------------------------------------------
#++

#
# This simple class encapsulates the functionality of this script. Essentially,
# we integrate using a branchspec and auto resolve with 'Accept Theirs'. This
# means that there's no support for maintaining variant branches here, only
# master/slave branches. Useful for so-called 'shared files' (VSS-style).
#
class IntegMgr

    def initialize( p4, branchspec )
	@p4 	=  p4
	@branch	=  branchspec
    end

    attr_reader :p4, :branch

    #
    # Integrate the specified change through the branch view and resolve
    # them.
    #
    def integrate( change )
	p4.run_sync
	c = create_change( change )
	p4.run_integrate( "-c", c, "-b", branch, "-s", 
						"//...@#{change},@#{change}" )
	p4.run_resolve( "-at" )

	# Build a list of the files to be submitted.
	filelist = p4.run_opened( "-c", c ).collect do
	    |h|
	    sprintf( "%s#%s (%s)", h[ "depotFile" ], h[ "rev" ], h[ "action" ] )
	end

	# If no files were opened for integrate, there's nothing to do, so
	# we just delete our pending changelist and get out of here
	if filelist.length == 0 
	    p4.delete_change( c )
	    return
	end

	# Now submit it. 
	p4.run_submit( "-c", c )

	admin_report do
	    "Change #{change} automatically integrated using branchspec " +
	    @branch + "\n\n"						  +
	    "Affected Files:\n\n\t"					  +
	    filelist.join( "\n\t" )					  +
	    "\n"
	end
    end

    # Create a new empty changelist for this transaction
    def create_change( changeno )
	spec = p4.fetch_change
	spec[ "Files" ] = Array.new
	spec[ "Jobs" ] 	= Array.new
	spec[ "Description" ] = "Automatically propagate change #{changeno} " +
				"to slave branch."
	change = p4.save_change( spec ).shift
	if( change =~ /^Change (\d+)/ )
	    return $1
	end
	raise( P4Exception, "Unable to create an empty pending changelist" )
    end
end

#
# Blurt out our syntax
#
def croaksyntax()
    puts <<EOS

Usage: autointeg.rb -b <branchspec> -c <changelist>

EOS
    exit 0
end

#
# Send a report by email to the admin
#
def admin_report( &block )
    msg = RMail::Message.new
    msg.header.to 	= ADMIN_EMAIL
    msg.header.from	= FROM_ADDRESS
    msg.header.subject	= MSG_SUBJECT
    msg.body = block.call()

    if DEBUG
	$stderr.puts( msg.to_s )
    end

    if EMAIL_REPORTS
	Net::SMTP.start( SMTP_SERVER ) do
	    |smtp|
	    smtp.sendmail( msg, FROM_ADDRESS, ADMIN_EMAIL )
	end
    end
end


#--
#-------------------------------------------------------------------------------
# Start of main script
#-------------------------------------------------------------------------------
#++

opts = GetoptLong.new( 
		[ "-b",		GetoptLong::REQUIRED_ARGUMENT ],
		[ "-c", 	GetoptLong::REQUIRED_ARGUMENT ]
		)

branch	= nil
change	= nil

# Parse command line
opts.each do
    |opt,arg|
    case opt
	when "-b" then	branch = arg
	when "-c" then	change = arg
    end
end

croaksyntax unless ( branch && change )

#
# Command line is valid. Initialize our Perforce client and get to work.
#
p4 = P4.new
p4.user 	= P4USER 	if P4USER
p4.client 	= P4CLIENT	if P4CLIENT
p4.port		= P4PORT	if P4PORT
p4.password	= P4PASSWD	if P4PASSWD

p4.parse_forms
p4.exception_level = 1
p4.debug = 0

begin
    p4.connect
    mgr = IntegMgr.new( p4, branch )
    mgr.integrate( change )
rescue P4Exception
    admin_report do
	"Automatic integration failed with errors. Detail follows\n\n" 	    +
	"Error: #{$!.message}\n\n" 					    +
	"Perforce Errors:\n\t"						    +
	p4.errors.join( "\n\t" )					    +
	"Traceback:\n\t"						    +
	$!.backtrace.join( "\n\t" )
    end
rescue
    admin_report do
	"Automatic integration failed with errors. Detail follows\n\n" 	    +
	"Error: #{$!.message}\n\n" 					    +
	"Traceback:\n\t"						    +
	$!.backtrace.join( "\n\t" )
    end
end
# Change User Description Committed
#3 6437 Tony Smith Update P4Ruby Library scripts to support Perforce P4Ruby 2007.3
rather than my old public depot P4Ruby.
#2 4765 Tony Smith Bug fix.
The script wasn't using the correct syntax for setting
the mail headers.
#1 4640 Tony Smith Add a sample post-commit trigger that can be used to keep a master
and slave branch in sync.