def runCLI(self, configFile, askToCreateRelease=False, forceSvnAuth=False): logger.info('-' * 79) logger.info(self.pkg) logger.info('-' * 79) logger.info('Start releasing new version of ' + self.pkg) # 1. Read the configuration file. logger.info('Loading configuration file: ' + configFile) config = ConfigParser.RawConfigParser() config.read(configFile) # 1.1. Get package index info. self.packageIndexUrl = config.get( base.BUILD_SECTION, 'package-index') self.packageIndexUsername = config.get( base.BUILD_SECTION, 'package-index-username') self.packageIndexPassword = config.get( base.BUILD_SECTION, 'package-index-password') # 1.2. Get svn repository info. self.svnRepositoryUrl = config.get( base.BUILD_SECTION, 'svn-repos') if forceSvnAuth: svnRepositoryUsername = config.get( base.BUILD_SECTION, 'svn-repos-username') svnRepositoryPassword = config.get( base.BUILD_SECTION, 'svn-repos-password') self.svn = base.SVN(svnRepositoryUsername, svnRepositoryPassword, forceAuth=True) else: self.svn = base.SVN() try: self.uploadType = config.get( base.BUILD_SECTION, 'upload-type') except ConfigParser.NoOptionError: self.uploadType = 'internal' try: self.tagLayout = config.get( base.BUILD_SECTION, 'tag-layout') except ConfigParser.NoOptionError: self.tagLayout = 'flat' # 1.3. Determine the possibly custom path. for pkg in config.get(base.BUILD_SECTION, 'packages').split(): if pkg.startswith(self.pkg): if ':' in pkg: self.customPath = pkg.split(':')[1] break # 2. Find all versions. versions = self.findVersions() logger.info('Existing %s versions: %s' % ( self.pkg, ' | '.join(reversed(versions)))) # 3. Determine the default version to suggest. defaultVersion = None # 3.1 Set default version based on forceVersion forceVersion = self.options.forceVersion if forceVersion: if forceVersion in versions: logger.error('Forced version %s already exists' % forceVersion) else: defaultVersion = forceVersion if versions and not defaultVersion: if self.options.nextVersion: # 3.2. If the branch was specified, check whether it changed # since the last release or if independent is set, if the last # release is based on the current branch changed = False if self.options.branch: logger.info("Checking for changes since version %s; please " "wait...", versions[-1]) changed = self.hasChangedSince(versions[-1], self.options.branch) if self.options.independent and not changed: # only check if not already marked as changed logger.info("Checking if last release is based on " "branch %s; please wait...", self.options.branch) if not self.isLastReleaseFromBranch(versions[-1], self.options.branch): changed = True if not changed: logger.info("No changes detected.") else: logger.info("Not checking for changes since version %s " "because no -b or --use-branch was specified.", versions[-1]) # 3.3. If the branch changed and the next version should be # suggested, let's find the next version. if changed: defaultVersion = base.guessNextVersion(versions[-1]) else: defaultVersion = versions[-1] else: logger.info("Not checking for changes because -n or " "--next-version was not used") defaultVersion = versions[-1] else: logger.info( "Not checking for changes because --force-version was used") # If there's no version the package is probably non existent if defaultVersion is None and self.options.defaultPackageVersion: # avoid interactive questions (handy for automated builds) defaultVersion = self.options.defaultPackageVersion branch = self.options.branch while True: version = base.getInput( 'Version for `%s`' %self.pkg, defaultVersion, self.options.useDefaults and defaultVersion is not None) if version not in versions and not self.options.offline: if askToCreateRelease: print 'The release %s-%s does not exist.' %(pkg, version) doRelease = base.getInput( 'Do you want to create it? yes/no', 'yes', self.options.useDefaults) if doRelease == 'no': continue # 4. Now create a release for this version. if not self.options.offline: # 4.1. Determine the branch from which to base the release # on. if branch is None: print 'Available Branches:' for branch in self.getBranches(): print ' * ' + branch print ' * trunk' branch = base.getInput( 'What branch do you want to use?', 'trunk', self.options.useDefaults) # 4.2. Create the release. self.createRelease(version, branch) break # 5. Return the version number. logger.info('Chosen version: ' + version) # save the info for build.py if branch is None: branch = 'trunk' self.branchUrl = self.getBranchURL(branch) self.branchRevision = self.getRevision(self.branchUrl) return version
def build(configFile, options): # save the time we started now = datetime.datetime.now() # Read the configuration file. logger.info('Loading configuration file: ' + configFile) config = base.NonDestructiveRawConfigParser() config.read(configFile) # Create the project config parser logger.info('Creating Project Configuration') projectParser = base.NonDestructiveRawConfigParser() template_path = None if config.has_option(base.BUILD_SECTION, 'template'): template = config.get(base.BUILD_SECTION, 'template') logger.info('Loading Project Configuration Template: ' + template) projectParser.read([template]) template_path = os.path.abspath(template) if not projectParser.has_section('versions'): projectParser.add_section('versions') # Determine all versions of the important packages pkgversions = {} pkginfos = {} for pkg in config.get(base.BUILD_SECTION, 'packages').split(): customPath = None if ':' in pkg: pkg, customPath = pkg.split(':') builder = package.PackageBuilder(pkg, options) version = builder.runCLI(configFile, askToCreateRelease=True, forceSvnAuth = options.forceSvnAuth) pkgversions[pkg] = version pkginfos[pkg] = (builder.branchUrl, builder.branchRevision) projectParser.set('versions', pkg, version) # Get upload type try: uploadType = config.get(base.BUILD_SECTION, 'buildout-upload-type') except ConfigParser.NoOptionError: uploadType = "webdav" # Stop if no buildout-server given try: config.get(base.BUILD_SECTION, 'buildout-server') except ConfigParser.NoOptionError: logger.info('No buildout-server specified in the cfg, STOPPING') logger.info('Selected package versions:\n%s' % ( '\n'.join('%s = %s' % (pkg, version) for pkg, version in pkgversions.items())) ) return # Write the new configuration file to disk projectName = config.get(base.BUILD_SECTION, 'name') defaultVersion = configVersion = config.get(base.BUILD_SECTION, 'version') projectVersions = findProjectVersions(projectName, config, options, uploadType) # Determine new project version if projectVersions: defaultVersion = projectVersions[-1] if options.nextVersion or configVersion == '+': defaultVersion = base.guessNextVersion(defaultVersion) if options.forceVersion: if options.forceVersion in projectVersions: logger.error('Forced version %s already exists' % options.forceVersion) else: defaultVersion = options.forceVersion projectVersion = base.getInput( 'Project Version', defaultVersion, options.useDefaults) # Write out the new project config -- the pinned versions projectConfigFilename = '%s-%s.cfg' % (projectName, projectVersion) logger.info('Writing project configuration file: ' + projectConfigFilename) projectParser.write(open(projectConfigFilename, 'w')) filesToUpload = [projectConfigFilename] try: hashConfigFiles = config.getboolean(base.BUILD_SECTION, 'hash-config-files') except ConfigParser.NoOptionError: hashConfigFiles = False # Process config files, check for dependent config files # we should make sure that they are on the server # by design only the projectConfigFilename will have variable dependencies if template_path: if hashConfigFiles: hashes = {} else: hashes = None dependencies = getDependentConfigFiles(os.path.dirname(template_path), projectConfigFilename, addSelf=False, outfile=projectConfigFilename, hashes=hashes) if hashConfigFiles: dependencies = addHashes(dependencies, hashes) #fix main config too addHashes([projectConfigFilename], hashes, rename=False) filesToUpload.extend(dependencies) # Dump package repo infos # do it here, projectConfigFilename might be rewritten by # getDependentConfigFiles projectFile = open(projectConfigFilename, 'a') projectFile.write('\n') projectFile.write('# package SVN infos:\n') for pkg, pkginfo in pkginfos.items(): projectFile.writelines( ('# %s\n' % pkg, '# svn URL:%s\n' % pkginfo[0], '# svn repo revision:%s\n' % pkginfo[1][0], '# svn last change revision:%s\n' % pkginfo[1][1], )) logger.info('SVN info: %s: %s %s %s', pkg, pkginfo[0], pkginfo[1][0], pkginfo[1][1]) projectFile.close() # Create deployment configurations # first define a parser for load addition variable (vars) section somewhere # in your templates chain. varsParser = base.NonDestructiveRawConfigParser() # make sure we use the right (tempalte inheritation) order varsParser.read(reversed(filesToUpload)) for section in config.sections(): if section == base.BUILD_SECTION: continue logger.info('Building deployment configuration: %s', section) template_path = config.get(section, 'template') logger.info('Loading deploy template file: %s', template_path) template = file(template_path, 'r').read() vars = dict([(name, value) for name, value in config.items(section) if name != 'template']) # apply additional vars defined in release template section if a # section name is defined as vars argument # or keep the vars argument as is if there is no section. This is # usefull if someone uses the vars attribute as argument (BBB) vName = vars.get('vars') if varsParser.has_section(vName): # apply vars from given section as additional vars for name, value in varsParser.items(vName): if name not in vars: # but only if not overriden in deployment config vars[name] = value # apply defaults vars['project-name'] = projectName vars['project-version'] = projectVersion vars['instance-name'] = section # add current time vars['current-datetime'] = now.isoformat() vars['current-date'] = now.date().isoformat() vars['current-time'] = now.time().isoformat() #handle multi-line items, ConfigParser removes leading spaces #we need to add some back otherwise it will be a parsing error for k, v in vars.items(): if '\n' in v: #add a 2 space indent vars[k] = v.replace('\n', '\n ') try: deployConfigText = template % vars except KeyError, e: logger.error("The %s deployment configuration is missing the %r setting required by %s", section, e.message, template_path) sys.exit(0) deployConfigFilename = '%s-%s-%s.cfg' %( config.get(base.BUILD_SECTION, 'name'), section, projectVersion) deployConfig = base.NonDestructiveRawConfigParser() deployConfig.readfp(StringIO.StringIO(deployConfigText)) deployConfig.set('buildout', 'extends', projectConfigFilename) logger.info('Writing deployment file: ' + deployConfigFilename) deployConfig.write(open(deployConfigFilename, 'w')) filesToUpload.append(deployConfigFilename)
def runCLI(self): # 1. Get the project to be installed. project = self.options.project if project is None: projects = self.getProjects() print 'Projects' for name in projects: print ' * ' + name project = base.getInput('Project', projects[0], False) # 2. Get the variant of the project. variant = self.options.variant if variant is None: variants = self.getVariants(project) print 'Variants' for name in variants: print ' * ' + name if not variants: logger.error( "No variants found, this script only works with variants.") sys.exit(0) variant = base.getInput('Variant', variants[0], False) # 3. Get the version of the project. version = self.options.version if version is None: versions = self.getVersions(project, variant) if len(versions) == 0: print "Sorry, but there have not been any", project, variant, "releases yet." sys.exit(0) if self.options.latest: version = versions[-1] else: print 'Versions' for name in versions: print ' * ' + name version = base.getInput('Version', versions[-1], False) # 4. Install the package url = self.options.url if self.options.username: #add username and password if present so that buildout can access #the URL without prompting parts = urlparse.urlparse(url) url = '%s://%s:%s@%s' % (parts[0], self.options.username, self.options.password, ''.join(parts[1:])) options = [] if self.options.verbose: options.append('-vv') if self.options.overrideDir: overrideDir = self.options.overrideDir #make it absolute if it's not #buildout does not like relative, buildbot cannot do absolute if is_win32: isAbs = overrideDir[0].lower().isalpha() and overrideDir[1]==':' if not isAbs: overrideDir = os.path.abspath(overrideDir) else: isAbs = overrideDir.startswith('/') if not isAbs: overrideDir = os.path.abspath(overrideDir) options.append('buildout:directory=%s' % overrideDir) cfgFile = '%s%s/%s-%s-%s.cfg' % (url, project, project, variant, version) base.do('%s -t %s %s -c %s' %( self.options.buildout, self.options.timeout, ' '.join(options), cfgFile), captureOutput=False)