def testPrintCurrentRevisionSyntaxError( self ):
		iface = BuildScriptInterface( BuildScriptInterfaceTests.SyntaxErrorBuildScriptName )
		try:
			iface.queryCurrentRevision()
			self.fail( 'The syntax error build script should throw an exception when querying the current revision.' )
		except MomError:
			pass
	def testQueryBuildNameSyntaxError( self ):
		iface = BuildScriptInterface( BuildScriptInterfaceTests.SyntaxErrorBuildScriptName )
		try:
			iface.querySetting( Settings.ScriptBuildName )
			self.fail( 'The syntax error build script should throw an exception when printing the build name.' )
		except MomError:
			pass
	def testPrintRevisionsSinceSyntaxError( self ):
		iface = BuildScriptInterface( BuildScriptInterfaceTests.SyntaxErrorBuildScriptName )
		try:
			iface.queryRevisionsSince( '8c758c1f1de2bcc19bda516f1acadf869ba28ee4' )
			self.fail( 'The syntax error build script should throw an exception when querying recent revisions.' )
		except MomError:
			pass
Exemplo n.º 4
0
	def registerNewRevisions( self, buildScript ):
		'''Determines new revisions committed since the last call with the same build script, 
		and adds those to the database.'''
		iface = BuildScriptInterface( buildScript )
		buildName = iface.querySetting( Settings.ScriptBuildName )
		newestBuildInfo = self.getNewestBuildInfo( buildScript )
		if newestBuildInfo:
			revision = newestBuildInfo.getRevision()
			mApp().debugN( self, 2, 'newest known revision for build script "{0}" ({1}) is "{2}"'
				.format( buildScript, buildName, revision ) )
			buildInfos = self.getBuildInfoForRevisionsSince( buildScript, buildName, revision )
			if buildInfos:
				mApp().message( self, 'build script "{0}" ({1}):'.format( buildScript, buildName ) )
				for buildInfo in buildInfos:
					msg = 'new revision "{0}"'.format( buildInfo.getRevision() )
					mApp().message( self, msg )
				self.saveBuildInfo( buildInfos )
			else:
				mApp().debug( self, 'no new revisions found for build script "{0}" ({1})'
					.format( buildScript, buildName ) )
		else:
			buildInfo = self.getBuildInfoForInitialRevision( buildScript, buildName )
			mApp().debug( self, 'saving initial revision "{0}" for build script "{1}" ({2})'
				.format( buildInfo.getRevision(), buildScript, buildName ) )
			self.saveBuildInfo( [ buildInfo ] )
Exemplo n.º 5
0
	def runBuildScriptTestBuild( self, buildScripts ):
		'''Execute a test build for every build script.
		If enabled on the command line arguments, SimpleCI calls every build script once, and then exits.'''
		error = False
		caughtException = False
		for script in buildScripts:
			iface = BuildScriptInterface( script )
			name = iface.querySetting( Settings.ScriptBuildName )
			buildInfo = self.getBuildStatus().getBuildInfoForInitialRevision( script, name )
			buildInfo.setBuildType( 's' )
			try:
				if self.getBuildStatus().performBuild( buildInfo ):
					self.message( self, 'build script test run finished successfully for "{0}".'.format( script ) )
				else:
					self.message( self, 'build script test run finished with an error for "{0}".'.format( script ) )
					error = True
			except MomError:
				self.message( self, 'build script test run triggered an exception for "{0}"'.format( script ) )
				caughtException = True
		if caughtException:
			raise MomError( 'exception during build script test runs.' )
		elif error:
			self.registerReturnCode( 1 )
		else:
			pass
Exemplo n.º 6
0
	def takeBuildInfoAndBuild( self, buildScripts ):
		'''Take a new revision from the build job list. Mark it as pending, and build it. Mark it as done afterwards.'''
		buildInfo = None
		# get the build names of the build scripts:
		buildNames = {}
		for buildScript in buildScripts:
			iface = BuildScriptInterface( buildScript )
			buildName = iface.querySetting( Settings.ScriptBuildName )
			if buildName:
				buildNames[ buildName ] = buildScript
			else:
				# this should not happen, since it was checked before
				mApp().debug( self, 'build script {0} is broken, ignoring.'.format( buildScript ) )
		with self.getConnection() as conn:
			buildInfos = self._loadBuildInfo( conn, BuildInfo.Status.NewRevision )
			for build in buildInfos:
				# the list is ordered by priority
				if build.getProjectName() in buildNames:
					build.setBuildStatus( BuildInfo.Status.Pending )
					self._updateBuildInfo( conn, build )
					buildInfo = build
					break
		if not buildInfo:
			return False
		try:
			self.performBuild( buildInfo )
		finally:
			with self.getConnection() as conn:
				buildInfo.setBuildStatus( BuildInfo.Status.Completed )
				self._updateBuildInfo( conn, buildInfo )
		return True
Exemplo n.º 7
0
	def getBuildInfoForInitialRevision( self, buildScript, projectName ):
		iface = BuildScriptInterface( buildScript )
		revision = iface.queryCurrentRevision()
		buildInfo = BuildInfo()
		buildInfo.setProjectName( projectName )
		buildInfo.setBuildStatus( BuildInfo.Status.InitialRevision )
		buildInfo.setRevision( revision )
		buildInfo.setBuildScript( buildScript )
		return buildInfo
Exemplo n.º 8
0
	def getRevisionsSinceForBranchBuilds( self, command, options, location, branch, tag ):
		path, tempdirs = self.fetchBuildScript()
		with TempFolderDeleter( tempdirs ):
			iface = BuildScriptInterface( path )
			buildName = iface.querySetting( Settings.ScriptBuildName )
			mApp().getSettings().set( Settings.ScriptBuildName, buildName )
			scm = getScm( location )
			scm.setParseBranchCommits( True )
			scm._handlePrintCommands( command, options )
Exemplo n.º 9
0
	def testQueryCharmProjectName( self ):
		buildDirectory = "charm_build"
		if os.path.isdir( buildDirectory ):
			self.fail( "Stale directory exists before the test starts: {0}".format( buildDirectory ) )
		iface = BuildScriptInterface( CharmBuildTests.BuildScriptName )
		projectNameQueryResult = iface.querySetting( Settings.ProjectName )
		self.assertTrue( projectNameQueryResult )
		# FIXME make the base dir queryable, so that we do not rely on a hardcoded name
		# the base directory should *NOT* have been created during the query:
		self.assertTrue( not os.path.isdir( "charm_build" ) )
Exemplo n.º 10
0
class BuildScriptInterfaceTests( MomTestCase ):

	ThisFilePath = os.path.realpath( os.path.dirname( __file__ ) )
	BuildScriptName = os.path.join( ThisFilePath, '..', 'buildscripts', 'example_mom_buildscript.py' )
	SyntaxErrorBuildScriptName = os.path.join( ThisFilePath, '..', 'buildscripts', 'syntax_error.py' )

	def setUp( self ):
		MomTestCase.setUp( self )
		self.iface = BuildScriptInterface( BuildScriptInterfaceTests.BuildScriptName )

	def tearDown( self ):
		MomTestCase.tearDown( self )
		rmtree( "make-o-matic" )

	def testQuerySetting( self ):
		variable = self.iface.querySetting( Settings.MomVersionNumber )
		self.assertEquals( variable, mApp().getSettings().get( Settings.MomVersionNumber ) )

	def testPrintCurrentRevision( self ):
		variable = self.iface.queryCurrentRevision()
		self.assertTrue( variable )

	def testPrintRevisionsSince( self ):
		revisions = self.iface.queryRevisionsSince( '8c758c1f1de2bcc19bda516f1acadf869ba28ee4' )
		self.assertTrue( len( revisions ) >= 5 )

	def testExecuteBuildScript( self ):
		runner = self.iface.execute( buildType = 'c', revision = 'HEAD', captureOutput = True )
		self.assertEqual( 0, runner.getReturnCode() )

	def testQueryBuildNameSyntaxError( self ):
		iface = BuildScriptInterface( BuildScriptInterfaceTests.SyntaxErrorBuildScriptName )
		try:
			iface.querySetting( Settings.ScriptBuildName )
			self.fail( 'The syntax error build script should throw an exception when printing the build name.' )
		except MomError:
			pass

	def testPrintRevisionsSinceSyntaxError( self ):
		iface = BuildScriptInterface( BuildScriptInterfaceTests.SyntaxErrorBuildScriptName )
		try:
			iface.queryRevisionsSince( '8c758c1f1de2bcc19bda516f1acadf869ba28ee4' )
			self.fail( 'The syntax error build script should throw an exception when querying recent revisions.' )
		except MomError:
			pass

	def testPrintCurrentRevisionSyntaxError( self ):
		iface = BuildScriptInterface( BuildScriptInterfaceTests.SyntaxErrorBuildScriptName )
		try:
			iface.queryCurrentRevision()
			self.fail( 'The syntax error build script should throw an exception when querying the current revision.' )
		except MomError:
			pass
Exemplo n.º 11
0
	def getNewestBuildInfo( self, buildScript ):
		iface = BuildScriptInterface( buildScript )
		buildName = iface.querySetting( Settings.ScriptBuildName )
		connection = self.getConnection()
		try:
			cursor = connection.cursor()
			query = 'select * from {0} where build_name=? order by id desc limit 1'.format( BuildStatus.TableName )
			cursor.execute( query, [ buildName ] )
			for row in cursor:
				buildInfo = self.__makeBuildInfoFromRow( row )
				return buildInfo # only the first (and only) result is interesting
		finally:
			cursor.close()
Exemplo n.º 12
0
	def checkBuildScripts( self, buildScripts ):
		'''Verify that the build scripts are working as expected.
		The method checks that the build script can be called with basic parameters.
		@return all build scripts that passed the test
		'''
		buildNames = []
		goodScripts = []
		for buildScript in buildScripts:
			iface = BuildScriptInterface( buildScript )
			try:
				name = iface.querySetting( Settings.ScriptBuildName )
				if name and name not in buildNames:
					buildNames.append( name )
					goodScripts.append( buildScript )
				else:
					self.error( self, 'Error in build script "{0}": The build name "{1}" is already used by another '
								'build script. Build script disregarded.'.format( buildScript, name ) )
			except MomError, e:
				self.error( self, 'Error in build script "{0}": Error querying the build name. Build script disregarded. Reason: {1}'
					.format( buildScript, e ) )
Exemplo n.º 13
0
	def getBuildInfoForRevisionsSince( self, buildScript, projectName, revision ):
		'''Return all revisions that modified the project since the specified revision.
		@return a list of BuildInfo object, with the latest commit last
		@throws MomEception, if any of the operations fail
		'''
		iface = BuildScriptInterface( buildScript )
		buildInfos = []
		lines = iface.queryRevisionsSince( revision )
		for line in lines:
			line = line.strip()
			if not line:
				continue

			buildInfo = BuildInfo()
			buildInfo.initializeFromPrintableRepresentation( line )
			buildInfo.setBuildStatus( buildInfo.Status.NewRevision )
			buildInfo.setBuildScript( buildScript )
			buildInfos.append( buildInfo )

		buildInfos.reverse()
		return buildInfos
Exemplo n.º 14
0
	def setUp( self ):
		MomTestCase.setUp( self )
		self.iface = BuildScriptInterface( BuildScriptInterfaceTests.BuildScriptName )
Exemplo n.º 15
0
	def performBuild( self, buildInfo ):
		"""Start a build process for a new revision. baseDir is the directory where all builds go. To build 
		different revisions and build types under it, subdirectories have to be used."""
		buildType = buildInfo.getBuildType().lower()
		# Under windows we have the problem that paths need to be short, so take only 7 digists of the git hash
		# this is also done for svn revision numbers, but these should not be so long
		if sys.platform == 'win32':
			rev = buildInfo.getRevision()[0:7]
		else:
			rev = buildInfo.getRevision()
		name = make_foldername_from_string( buildInfo.getProjectName() )
		# find suitable names for the different build dirs:
		baseDir = os.path.join( os.getcwd(), 'builds' )
		buildRoot = mApp().getSettings().get( Settings.SimpleCIBuildDirectory, required = False ) or baseDir
		subfolder = make_foldername_from_string( rev )
		directory = os.path.normpath( os.path.join( buildRoot, name, buildType, subfolder ) )
		# prepare build directory:
		if os.path.isdir( directory ):
			mApp().debug( self, 'found remainders of a previous build, nuking it...' )
			try:
				rmtree( directory )
				mApp().debug( self, '...that was good!' )
			except ( OSError, IOError ) as e:
				raise ConfigurationError( 'Remnants of a previous build exist at "{0}" and cannot be deleted, bad. Reason: {1}.'
					.format( directory, e ) )
		try:
			os.makedirs( directory )
		except ( OSError, IOError )as e:
			raise ConfigurationError( 'Cannot create required build directory "{0}"!'.format( directory ) )
		mApp().message( self, 'starting build job for project "{0}" at revision {1}.'
					.format( buildInfo.getProjectName(), rev ) )
		with EnvironmentSaver():
			os.chdir( directory )
			extend_debug_prefix( buildInfo.getProjectName() )
			iface = BuildScriptInterface( os.path.abspath( buildInfo.getBuildScript() ) )
			runner = iface.executeBuildInfo( buildInfo )
			try:
				with open( 'buildscript.log', 'w' ) as f:
					text = runner.getStdOutAsString()
					f.write( text.decode() )
			except Exception as e:
				mApp().message( self, 'Problem! saving the build script output failed during handling an exception! {0}'
					.format( e ) )
			if runner.getReturnCode() != 0:
				mApp().message( self, 'build failed for project "{0}" at revision {1}'.format( buildInfo.getProjectName(), rev ) )
				# FIXME send out email reports on configuration or MOM errors
				mApp().message( self, 'exit code {0}'.format( runner.getReturnCode() ) )
				print( """\
-->   ____        _ _     _   _____     _ _          _ 
-->  | __ ) _   _(_) | __| | |  ___|_ _(_) | ___  __| |
-->  |  _ \| | | | | |/ _` | | |_ / _` | | |/ _ \/ _` |
-->  | |_) | |_| | | | (_| | |  _| (_| | | |  __/ (_| |
-->  |____/ \__,_|_|_|\__,_| |_|  \__,_|_|_|\___|\__,_|
--> 
""" )
				return False
			else:
				mApp().message( self, 'build succeeded for project "{0}" at revision {1}'.format( buildInfo.getProjectName(), rev ) )
				print( """\
-->   _         _ _    _      _
-->  | |__ _  _(_) |__| |  __| |___ _ _  ___
-->  | '_ \ || | | / _` | / _` / _ \ ' \/ -_)
-->  |_.__/\_,_|_|_\__,_| \__,_\___/_||_\___|
--> 
""" )
				return True
Exemplo n.º 16
0
	def invokeBuild( self, args, timeout = None ):
		path, tempdirs = self.fetchBuildScript()
		with TempFolderDeleter( tempdirs ):
			iface = BuildScriptInterface( path )
			runner = iface.executeWithArgs( timeout = timeout, args = args )
			return runner