def package_all(self, version=None): """Repackage files to be uploaded. 'version': version to package; defaults to the current tag (without the 'release-' prefix.""" if not self.repo.is_nuxeoecm: log("Skip packaging step (not a main Nuxeo repository).") return self.archive_dir = os.path.abspath(os.path.join(self.repo.basedir, os.pardir, "archives")) if os.path.isdir(self.archive_dir): shutil.rmtree(self.archive_dir) os.mkdir(self.archive_dir) self.tmpdir = tempfile.mkdtemp() if version is None: version = self.tag # Tomcat and JBoss packages for old, new in PKG_RENAMINGS.items(): self.package(old % version, new % version) # Tomcat SDK packages for old, new in PKG_RENAMINGS_OPTIONALS.items(): self.package(old % version, new % version, False) self.package_sources(version) shutil.rmtree(self.tmpdir)
def __init__(self, alias, restart_from, default_conf=None, marketplace_conf=None): self.alias = alias self.restart_from = restart_from if marketplace_conf == '': marketplace_conf = DEFAULT_MP_CONF_URL self.marketplace_conf = marketplace_conf cwd = os.getcwd() if os.path.isdir(os.path.join(cwd, "marketplace")): pass elif os.path.split(cwd)[1] == "marketplace": cwd = os.path.abspath(os.path.join(cwd, os.pardir)) else: if '__file__' not in locals(): __file__ = inspect.getframeinfo(inspect.currentframe())[0] # @ReservedAssignment cwd = os.path.dirname(os.path.abspath(__file__)) cwd = os.path.abspath(os.path.join(cwd, os.pardir)) log("Nuxeo source location: %s" % cwd) self.repo = Repository(cwd, self.alias) self.defaults = {} if default_conf: default_info = ReleaseInfo() default_info.read_release_log(default_conf) prefix = default_info.module for key, value in vars(default_info).iteritems(): self.defaults[prefix + "-" + key] = str(value) self.mp_config = self.repo.get_mp_config(self.marketplace_conf, self.defaults)
def __init__(self, alias, restart_from, default_conf=None, marketplace_conf=None): self.alias = alias self.restart_from = restart_from if marketplace_conf == '': marketplace_conf = DEFAULT_MP_CONF_URL self.marketplace_conf = marketplace_conf cwd = os.getcwd() if os.path.isdir(os.path.join(cwd, "marketplace")): pass elif os.path.split(cwd)[1] == "marketplace": cwd = os.path.abspath(os.path.join(cwd, os.pardir)) else: if '__file__' not in locals(): __file__ = inspect.getframeinfo( inspect.currentframe())[0] # @ReservedAssignment cwd = os.path.dirname(os.path.abspath(__file__)) cwd = os.path.abspath(os.path.join(cwd, os.pardir)) log("Nuxeo source location: %s" % cwd) self.repo = Repository(cwd, self.alias) self.defaults = {} if default_conf: default_info = ReleaseInfo() default_info.read_release_log(default_conf) prefix = default_info.module for key, value in vars(default_info).iteritems(): self.defaults[prefix + "-" + key] = str(value) self.mp_config = self.repo.get_mp_config(self.marketplace_conf, self.defaults)
def main(): assert_git_config() try: usage = ("""usage: %prog <command> [options] %prog clone [-r alias] [-m URL] %prog branch [-r alias] [-m URL] [--rf package] [--dryrun] %prog prepare [-r alias] [-m URL] [--rf package] [--dryrun] %prog perform [-r alias] [-m URL] [--rf package] [--dryrun]""") description = """Release Nuxeo Packages.\n The first call must provide an URL for the configuration. If set to '' (empty string), it defaults to '%s'. You can use a local file URL ('file://').\n Then, a 'release.ini' file is generated and will be reused for the next calls. For each package, a 'release-$PACKAGE_NAME.log' file is also generated and corresponds to the file generated by the release.py script.\n The 'release.ini' file contains informations about the release process:\n - 'prepared = True' if the prepare task succeeded,\n - 'performed = True' if the perform task succeeded,\n - 'uploaded = ...' if an upload successfully happened,\n - 'skip = Failed!' followed by a stack trace in case of error.\n The script can be re-called: it will skip the packages with a skip value and skip the prepare (or perform) if 'prepared = True' (or 'performed = True').\n Failed uploads are not retried and must be manually done.""" % DEFAULT_MP_CONF_URL help_formatter = IndentedHelpFormatterWithNL(max_help_position=7, width=get_terminal_size()[0]) parser = optparse.OptionParser(usage=usage, description=description, formatter=help_formatter) parser.add_option('-r', action="store", type="string", dest='remote_alias', default='origin', help="""The Git alias of remote URL. Default: '%default'""") parser.add_option('-m', "--marketplace-conf", action="store", type="string", dest='marketplace_conf', default=None, help="""The Marketplace configuration URL. Default: '%default'""") parser.add_option('-i', '--interactive', action="store_true", dest='interactive', default=False, help="""Not implemented (TODO NXP-8573). Interactive mode. Default: '%default'""") parser.add_option('--rf', '--restart-from', action="store", dest='restart_from', default=None, help="""Restart from a package. Default: '%default'""") parser.add_option('--dryrun', action="store_true", dest='dryrun', default=False, help="""Dry run mode. Default: '%default'""") (options, args) = parser.parse_args() if len(args) == 1: command = args[0] elif len(args) > 1: raise ExitException(1, "'command' must be a single argument. See usage with '-h'.") full_release = ReleaseMP(options.remote_alias, options.restart_from, options.marketplace_conf) if "command" not in locals(): raise ExitException(1, "Missing command. See usage with '-h'.") elif command == "clone": full_release.clone() elif command == "branch": full_release.release_branch(dryrun=options.dryrun) elif command == "prepare": full_release.prepare(dryrun=options.dryrun) elif command == "perform": full_release.perform(dryrun=options.dryrun) elif command == "test": full_release.test() else: raise ExitException(1, "Unknown command! See usage with '-h'.") except ExitException, e: if e.message is not None: log("[ERROR] %s" % e.message, sys.stderr) sys.exit(e.return_code)
def perform(self): """ Perform the release: push source, deploy artifacts and upload packages.""" cwd = os.getcwd() marketplaces = self.mp_config.sections() if self.restart_from: idx = marketplaces.index(self.restart_from) marketplaces = marketplaces[idx:] for marketplace in marketplaces: if self.mp_config.has_option(marketplace, "skip"): log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) continue if not self.mp_config.getboolean(marketplace, "prepared"): log("[WARN] Skipped '%s' (%s)" % (marketplace, "Not prepared")) continue if self.mp_config.getboolean(marketplace, "performed"): log("Skipped '%s' (%s)" % (marketplace, "Already performed")) continue try: log("Perform %s" % marketplace) os.chdir(os.path.join(self.repo.mp_dir, marketplace)) mp_repo = Repository(os.getcwd(), self.alias) # Perform release (_, branch, tag, next_snapshot, maintenance_version, is_final, skipTests, _, other_versions, _, _) = Release.read_release_log(mp_repo.basedir) mp_release = Release(mp_repo, branch, tag, next_snapshot, maintenance_version, is_final=is_final, skipTests=skipTests, other_versions=other_versions) mp_release.perform() performed = True except: stack = traceback.format_exc() log("[ERROR] %s" % stack) performed = False self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "performed", performed) self.repo.save_mp_config(self.mp_config) if performed: # Upload on Connect for dirpath, _, filenames in os.walk(mp_repo.basedir): for name in filenames: path = os.path.join(dirpath, name) if (os.path.isfile(path) and fnmatch.fnmatch(path[len(mp_repo.basedir) + 1:], self.mp_config.get(marketplace, "mp_to_upload"))): self.upload(CONNECT_PROD_URL, path) self.mp_config.set(marketplace, "uploaded", CONNECT_PROD_URL + ": " + path) self.repo.save_mp_config(self.mp_config) os.chdir(cwd)
def update_versions(self, old_version, new_version): """Update all occurrences of 'old_version' with 'new_version'.""" log("Replacing occurrences of %s with %s" % (old_version, new_version)) pattern = re.compile("^.*\\.(xml|properties|txt|defaults|sh|html|nxftl)$") for root, dirs, files in os.walk(os.getcwd(), True, None, True): for dir in set(dirs) & set([".git", "target"]): dirs.remove(dir) for name in files: replaced = False if fnmatch.fnmatch(name, "pom*.xml"): tree = etree.parse(os.path.join(root, name)) # Parent POM version parent = tree.getroot().find("pom:parent", namespaces) if parent is not None: elem = parent.find("pom:version", namespaces) if elem is not None and elem.text == old_version: elem.text = new_version replaced = True # POM version elem = tree.getroot().find("pom:version", namespaces) if elem is not None and elem.text == old_version: elem.text = new_version replaced = True # Properties like nuxeo.*.version prop_pattern = re.compile("{" + namespaces.get("pom") + "}nuxeo\..*version") properties = tree.getroot().find("pom:properties", namespaces) if properties is not None: for property in properties.getchildren(): if (not isinstance(property, etree._Comment) and prop_pattern.match(property.tag) and property.text == old_version): property.text = new_version replaced = True tree.write_c14n(os.path.join(root, name)) elif pattern.match(name): with open(os.path.join(root, name), "rb") as f: content = f.read() if content.find(old_version) > -1: replaced = True content = content.replace(old_version, new_version) with open(os.path.join(root, name), "wb") as f: f.write(content) if replaced: log(os.path.join(root, name))
def __init__(self, alias, restart_from, marketplace_conf=None): self.alias = alias self.restart_from = restart_from if marketplace_conf == '': marketplace_conf = DEFAULT_MP_CONF_URL self.marketplace_conf = marketplace_conf cwd = os.getcwd() if os.path.isdir(os.path.join(cwd, "marketplace")): pass elif os.path.split(cwd)[1] == "marketplace": cwd = os.path.abspath(os.path.join(cwd, os.pardir)) else: if '__file__' not in locals(): __file__ = inspect.getframeinfo(inspect.currentframe())[0] # @ReservedAssignment cwd = os.path.dirname(os.path.abspath(__file__)) cwd = os.path.abspath(os.path.join(cwd, os.pardir)) log("Nuxeo source location: %s" % cwd) self.repo = Repository(cwd, self.alias) self.mp_config = self.repo.get_mp_config(self.marketplace_conf)
def __init__(self, alias, restart_from, marketplace_conf=None): self.alias = alias self.restart_from = restart_from if marketplace_conf == '': marketplace_conf = DEFAULT_MP_CONF_URL self.marketplace_conf = marketplace_conf cwd = os.getcwd() if os.path.isdir(os.path.join(cwd, "marketplace")): pass elif os.path.split(cwd)[1] == "marketplace": cwd = os.path.abspath(os.path.join(cwd, os.pardir)) else: if '__file__' not in locals(): __file__ = inspect.getframeinfo(inspect.currentframe())[0] cwd = os.path.dirname(os.path.abspath(__file__)) cwd = os.path.abspath(os.path.join(cwd, os.pardir)) log("Nuxeo source location: %s" % cwd) self.repo = Repository(cwd, self.alias) self.mp_config = self.repo.get_mp_config(self.marketplace_conf)
def __init__(self, repo, branch, tag, next_snapshot, maintenance="auto", is_final=False, skipTests=False): self.repo = repo self.branch = branch self.is_final = is_final self.maintenance = maintenance self.skipTests = skipTests # Evaluate default values, if not provided self.set_snapshot() self.set_tag(tag) self.set_next_snapshot(next_snapshot) # Detect if working on Nuxeo main sources tree = etree.parse(os.path.join(self.repo.basedir, "pom.xml")) artifact_id = tree.getroot().find("pom:artifactId", namespaces) self.repo.is_nuxeoecm = "nuxeo-ecm" == artifact_id.text if self.repo.is_nuxeoecm: log("Releasing Nuxeo main repository...") else: log("Releasing custom repository...")
def prepare(self, dryrun=False): """ Prepare the release.""" cwd = os.getcwd() marketplaces = self.mp_config.sections() if self.restart_from: idx = marketplaces.index(self.restart_from) marketplaces = marketplaces[idx:] for marketplace in marketplaces: if self.mp_config.has_option(marketplace, "skip"): log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) continue if self.mp_config.getboolean(marketplace, "prepared"): log("Skipped '%s' (%s)" % (marketplace, "Already prepared")) continue try: log("Prepare %s" % marketplace) os.chdir(os.path.join(self.repo.mp_dir, marketplace)) mp_repo = Repository(os.getcwd(), self.alias) # Prepare release mp_release = Release(mp_repo, self.mp_config.get(marketplace, "branch"), self.mp_config.get(marketplace, "tag"), self.mp_config.get(marketplace, "next_snapshot"), self.mp_config.get(marketplace, "maintenance_version"), is_final=True, skipTests=False, other_versions=self.mp_config.get( marketplace, "other_versions", None)) mp_release.log_summary() mp_release.prepare(dryrun=dryrun) prepared = True except: stack = traceback.format_exc() log("[ERROR] %s" % stack) prepared = False self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "prepared", prepared) self.repo.save_mp_config(self.mp_config) if (prepared): # Upload on Connect test for dirpath, _, filenames in os.walk(mp_repo.basedir): for name in filenames: path = os.path.join(dirpath, name) if (os.path.isfile(path) and fnmatch.fnmatch(path[len(mp_repo.basedir) + 1:], self.mp_config.get(marketplace, "mp_to_upload"))): self.upload(CONNECT_TEST_URL, path) self.mp_config.set(marketplace, "uploaded", CONNECT_TEST_URL + ": " + path) self.repo.save_mp_config(self.mp_config) os.chdir(cwd)
def package(self, old_archive, new_name, failonerror=True): """Repackage a ZIP following the rules: - have a parent directory with the same name as the archive name - set executable bit on scripts in bin/ - activate the setup wizard If 'failonerror', raise an ExitException in case of missing file.""" if not os.path.isfile(old_archive): if failonerror: raise ExitException(1, "Could not find %s" % old_archive) else: log("[WARN] Could not find %s" % old_archive, sys.stderr) return new_archive = os.path.join(self.archive_dir, new_name + ".zip") extract_zip(old_archive, os.path.join(self.tmpdir, new_name)) log("Packaging %s ..." % new_archive) cwd = os.getcwd() os.chdir(os.path.join(self.tmpdir, new_name)) ls = os.listdir(os.curdir) if len(ls) == 1: if ls[0] != new_name: shutil.move(ls[0], new_name) else: os.mkdir(new_name) for file in ls: shutil.move(file, os.path.join(new_name, file)) files = os.listdir(os.path.join(new_name, "bin")) for filename in (fnmatch.filter(files, "*ctl") + fnmatch.filter(files, "*.sh") + fnmatch.filter(files, "*.command")): os.chmod(os.path.join(new_name, "bin", filename), 0744) with open(os.path.join(new_name, "bin", "nuxeo.conf"), "a") as f: f.write("nuxeo.wizard.done=false\n") make_zip(os.path.join(self.archive_dir, new_name + ".zip"), os.getcwd(), new_name) os.chdir(cwd) # Cleanup temporary directory shutil.rmtree(os.path.join(self.tmpdir, new_name))
def prepare(self, dryrun=False): """ Prepare the release.""" cwd = os.getcwd() if not os.path.isdir(self.repo.mp_dir): self.clone() os.chdir(self.repo.mp_dir) marketplaces_skipped = [] for marketplace in self.get_packages_list(): log("") if self.mp_config.has_option(marketplace, "skip"): log("[%s]" % marketplace) log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if self.mp_config.getboolean(marketplace, "prepared"): log("[%s]" % marketplace) log("Skipped '%s' (%s)" % (marketplace, "Already prepared")) continue try: mp_dir = os.path.join(self.repo.mp_dir, marketplace) if not os.path.isdir(mp_dir): os.chdir(self.repo.mp_dir) self.repo.git_pull(marketplace, self.mp_config.get(marketplace, "branch")) else: log("[%s]" % marketplace) os.chdir(mp_dir) mp_repo = Repository(os.getcwd(), self.alias) if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Prepare release of %s..." % marketplace) release_info = ReleaseInfo(module=marketplace, remote_alias=self.alias, branch=self.mp_config.get(marketplace, "branch"), tag=self.mp_config.get(marketplace, "tag"), next_snapshot=self.mp_config.get(marketplace, "next_snapshot"), maintenance_version=self.mp_config.get(marketplace, "maintenance_version"), is_final=self.mp_config.getboolean(marketplace, "is_final"), skip_tests=self.mp_config.getboolean(marketplace, "skipTests"), skip_its=self.mp_config.getboolean(marketplace, "skipITs"), profiles=self.mp_config.get(marketplace, "profiles"), other_versions=self.mp_config.get(marketplace, "other_versions"), #files_pattern, props_pattern, msg_commit, msg_tag, auto_increment_policy=self.mp_config.get(marketplace, "auto_increment_policy"), dryrun=dryrun) mp_release = Release(mp_repo, release_info) release_log = mp_release.log_summary() release_info.read_release_log(release_log) if dryrun: print "DEBUG -- init %s with:" % marketplace for key, value in vars(release_info).iteritems(): if dryrun: print "DEBUG: %s-%s=%s" % (marketplace, key, value) self.mp_config.set("DEFAULT", marketplace + "-" + key, str(value)) if dryrun: print mp_release.prepare(dryrun=dryrun, upgrade_only=upgrade_only, dodeploy=True) prepared = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) prepared = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "prepared", str(prepared)) self.repo.save_mp_config(self.mp_config) if prepared and not upgrade_only: owner = None if self.mp_config.has_option(marketplace, "owner"): owner = self.mp_config.get(marketplace, "owner") self.upload(CONNECT_TEST_URL, marketplace, dryrun=dryrun, owner=owner)
def perform(self, dryrun=False): """ Perform the release: push source, deploy artifacts and upload packages.""" cwd = os.getcwd() marketplaces = self.mp_config.sections() marketplaces_skipped = [] if self.restart_from: idx = marketplaces.index(self.restart_from) marketplaces = marketplaces[idx:] for marketplace in marketplaces: log("") if self.mp_config.has_option(marketplace, "skip"): log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if not self.mp_config.getboolean(marketplace, "prepared"): log("[WARN] Skipped '%s' (%s)" % (marketplace, "Not prepared")) continue if self.mp_config.getboolean(marketplace, "performed"): log("Skipped '%s' (%s)" % (marketplace, "Already performed")) continue try: if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Perform %s" % marketplace) os.chdir(os.path.join(self.repo.mp_dir, marketplace)) mp_repo = Repository(os.getcwd(), self.alias) # Perform release (_, branch, tag, next_snapshot, maintenance_version, is_final, skipTests, skipITs, _, other_versions, _, _) = Release.read_release_log(mp_repo.basedir) mp_release = Release(mp_repo, branch, tag, next_snapshot, maintenance_version, is_final=is_final, skipTests=skipTests, skipITs=skipITs, other_versions=other_versions) mp_release.perform(dryrun=dryrun, upgrade_only=upgrade_only) performed = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) performed = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "performed", str(performed)) self.repo.save_mp_config(self.mp_config) if performed and not upgrade_only: # Upload on Connect for dirpath, _, filenames in os.walk(mp_repo.basedir): for name in filenames: path = os.path.join(dirpath, name) if (os.path.isfile(path) and fnmatch.fnmatch(path[len(mp_repo.basedir) + 1:], self.mp_config.get(marketplace, "mp_to_upload"))): self.upload(CONNECT_PROD_URL, path, dryrun=dryrun) self.mp_config.set(marketplace, "uploaded", CONNECT_PROD_URL + ": " + path) self.repo.save_mp_config(self.mp_config)
def log_summary(self, store_params=True): """Log summary of configuration for current release.""" log("Releasing from branch:".ljust(25) + self.branch) log("Current version:".ljust(25) + self.snapshot) log("Tag:".ljust(25) + "release-" + self.tag) log("Next version:".ljust(25) + self.next_snapshot) if self.maintenance == "auto": log("No maintenance branch".ljust(25)) else: log("Maintenance version:".ljust(25) + self.maintenance) if self.skipTests: log("Tests execution is skipped") if store_params: release_log = os.path.abspath(os.path.join(self.repo.basedir, os.pardir, "release.log")) with open(release_log, "wb") as f: f.write("REMOTE=%s\nBRANCH=%s\nTAG=%s\nNEXT_SNAPSHOT=%s\n" "MAINTENANCE=%s\nFINAL=%s\nSKIP_TESTS=%s" % (self.repo.alias, self.branch, self.tag, self.next_snapshot, self.maintenance, self.is_final, self.skipTests)) log("Parameters stored in %s" % release_log) log("")
def package_all(self, version=None): """Repackage files to be uploaded. 'version': version to package; defaults to the current tag (without the 'release-' prefix.""" self.archive_dir = os.path.abspath(os.path.join(self.repo.basedir, os.pardir, "archives")) if os.path.isdir(self.archive_dir): shutil.rmtree(self.archive_dir) os.mkdir(self.archive_dir) self.tmpdir = tempfile.mkdtemp() if version is None: version = self.tag # Tomcat and JBoss packages for old, new in PKG_RENAMINGS.items(): self.package(old % version, new % version) # Tomcat SDK packages for old, new in PKG_RENAMINGS_OPTIONALS.items(): self.package(old % version, new % version, False) # Online (aka light) Tomcat package offline_name = "nuxeo-cap-%s-tomcat" % version extract_zip(os.path.join(self.archive_dir, offline_name + ".zip"), self.tmpdir) # Generate online package if packages.xml exists if os.path.isfile(os.path.join(self.tmpdir, offline_name, "setupWizardDownloads", "packages.xml")): online_name = "nuxeo-cap-%s-tomcat-online" % version shutil.move(os.path.join(self.tmpdir, offline_name, "setupWizardDownloads", "packages.xml"), os.path.join(self.archive_dir, "packages.xml")) # Remove Marketplace packages shutil.rmtree(os.path.join(self.tmpdir, offline_name, "setupWizardDownloads")) shutil.move(os.path.join(self.tmpdir, offline_name), os.path.join(self.tmpdir, online_name)) make_zip(os.path.join(self.archive_dir, online_name + ".zip"), os.path.join(self.tmpdir, online_name), online_name) # Marketplace packages archive_mp_dir = os.path.join(self.archive_dir, "mp") if not os.path.isdir(archive_mp_dir): os.mkdir(archive_mp_dir) # Copy and rename MP to archive directory for old, new in MP_RENAMINGS.items(): shutil.copy2(old % version, os.path.join(archive_mp_dir, new % version)) log("Checking packages integrity...") for package in os.listdir(archive_mp_dir): m = hashlib.md5() with open(os.path.join(archive_mp_dir, package), "rb") as f: m.update(f.read()) package_md5 = m.hexdigest() found_package = False found_package_md5 = False for line in open(os.path.join(self.archive_dir, "packages.xml")): if package in line: found_package = True if package_md5 in line: found_package_md5 = True if found_package and found_package_md5: break if not found_package: log("[ERROR] Could not find %s in packages.xml" % package, sys.stderr) if not found_package_md5: log("[ERROR] %s MD5 did not match packages.xml information" % package, sys.stderr) log("Done.") self.package_sources(version) shutil.rmtree(self.tmpdir)
def perform(self, dryrun=False): """ Perform the release: push source, deploy artifacts and upload packages.""" cwd = os.getcwd() marketplaces = self.mp_config.sections() marketplaces_skipped = [] if self.restart_from: idx = marketplaces.index(self.restart_from) marketplaces = marketplaces[idx:] for marketplace in marketplaces: log("") if self.mp_config.has_option(marketplace, "skip"): log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if not self.mp_config.getboolean(marketplace, "prepared"): log("[WARN] Skipped '%s' (%s)" % (marketplace, "Not prepared")) continue if self.mp_config.getboolean(marketplace, "performed"): log("Skipped '%s' (%s)" % (marketplace, "Already performed")) continue try: if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Perform %s" % marketplace) os.chdir(os.path.join(self.repo.mp_dir, marketplace)) mp_repo = Repository(os.getcwd(), self.alias) # Perform release (_, branch, tag, next_snapshot, maintenance_version, is_final, skipTests, skipITs, _, other_versions, _, _) = Release.read_release_log(mp_repo.basedir) mp_release = Release(mp_repo, branch, tag, next_snapshot, maintenance_version, is_final=is_final, skipTests=skipTests, skipITs=skipITs, other_versions=other_versions) mp_release.perform(dryrun=dryrun, upgrade_only=upgrade_only) performed = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) performed = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "performed", str(performed)) self.repo.save_mp_config(self.mp_config) if performed and not upgrade_only: # Upload on Connect for dirpath, _, filenames in os.walk(mp_repo.basedir): for name in filenames: path = os.path.join(dirpath, name) if (os.path.isfile(path) and fnmatch.fnmatch( path[len(mp_repo.basedir) + 1:], self.mp_config.get(marketplace, "mp_to_upload"))): self.upload(CONNECT_PROD_URL, path, dryrun=dryrun) self.mp_config.set(marketplace, "uploaded", CONNECT_PROD_URL + ": " + path) self.repo.save_mp_config(self.mp_config)
def prepare(self, dryrun=False): """ Prepare the release.""" cwd = os.getcwd() if not os.path.isdir(self.repo.mp_dir): self.clone() os.chdir(self.repo.mp_dir) marketplaces_skipped = [] for marketplace in self.get_packages_list(): log("") if self.mp_config.has_option(marketplace, "skip"): log("[%s]" % marketplace) log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if self.mp_config.getboolean(marketplace, "prepared"): log("[%s]" % marketplace) log("Skipped '%s' (%s)" % (marketplace, "Already prepared")) continue try: mp_dir = os.path.join(self.repo.mp_dir, marketplace) if not os.path.isdir(mp_dir): os.chdir(self.repo.mp_dir) self.repo.git_pull(marketplace, self.mp_config.get(marketplace, "branch")) else: log("[%s]" % marketplace) os.chdir(mp_dir) mp_repo = Repository(os.getcwd(), self.alias) if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Prepare release of %s..." % marketplace) mp_release = Release(mp_repo, self.mp_config.get(marketplace, "branch"), self.mp_config.get(marketplace, "tag"), self.mp_config.get(marketplace, "next_snapshot"), self.mp_config.get(marketplace, "maintenance_version"), is_final=True, skipTests=self.mp_config.getboolean(marketplace, "skipTests"), skipITs=self.mp_config.getboolean(marketplace, "skipITs"), other_versions=self.mp_config.get(marketplace, "other_versions", None)) mp_release.log_summary() mp_release.prepare(dryrun=dryrun, upgrade_only=upgrade_only, dodeploy=True) prepared = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) prepared = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "prepared", str(prepared)) self.repo.save_mp_config(self.mp_config) if prepared and not upgrade_only: self.upload(CONNECT_TEST_URL, marketplace, dryrun=dryrun)
def prepare(self, dryrun=False): """ Prepare the release.""" cwd = os.getcwd() if not os.path.isdir(self.repo.mp_dir): self.clone() os.chdir(self.repo.mp_dir) marketplaces = self.mp_config.sections() marketplaces_skipped = [] if self.restart_from: idx = marketplaces.index(self.restart_from) marketplaces = marketplaces[idx:] for marketplace in marketplaces: log("") if self.mp_config.has_option(marketplace, "skip"): log("[%s]" % marketplace) log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if self.mp_config.getboolean(marketplace, "prepared"): log("[%s]" % marketplace) log("Skipped '%s' (%s)" % (marketplace, "Already prepared")) continue try: mp_dir = os.path.join(self.repo.mp_dir, marketplace) if not os.path.isdir(mp_dir): os.chdir(self.repo.mp_dir) self.repo.git_pull( marketplace, self.mp_config.get(marketplace, "branch")) else: log("[%s]" % marketplace) os.chdir(mp_dir) mp_repo = Repository(os.getcwd(), self.alias) if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Prepare release of %s..." % marketplace) mp_release = Release( mp_repo, self.mp_config.get(marketplace, "branch"), self.mp_config.get(marketplace, "tag"), self.mp_config.get(marketplace, "next_snapshot"), self.mp_config.get(marketplace, "maintenance_version"), is_final=True, skipTests=False, skipITs=False, other_versions=self.mp_config.get(marketplace, "other_versions", None)) mp_release.log_summary() mp_release.prepare(dryrun=dryrun, upgrade_only=upgrade_only, dodeploy=True) prepared = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) prepared = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "prepared", str(prepared)) self.repo.save_mp_config(self.mp_config) if prepared and not upgrade_only: # Upload on Connect test for dirpath, _, filenames in os.walk(mp_repo.basedir): for name in filenames: path = os.path.join(dirpath, name) if (os.path.isfile(path) and fnmatch.fnmatch( path[len(mp_repo.basedir) + 1:], self.mp_config.get(marketplace, "mp_to_upload"))): self.upload(CONNECT_TEST_URL, path, dryrun=dryrun) self.mp_config.set(marketplace, "uploaded", CONNECT_TEST_URL + ": " + path) self.repo.save_mp_config(self.mp_config)
def main(): global namespaces assert_git_config() namespaces = {"pom": "http://maven.apache.org/POM/4.0.0"} etree.register_namespace('pom', 'http://maven.apache.org/POM/4.0.0') try: if not os.path.isdir(".git"): raise ExitException(1, "That script must be ran from root of a Git" + " repository") usage = ("usage: %prog [options] <command>\n\nCommands:\n" " prepare: Prepare the release (build, change versions, tag " "and package source and distributions). The release " "parameters are stored in a release.log file.\n" " perform: Perform the release (push sources, deploy " "artifacts and upload packages). If no parameter is given, " "they are read from the release.log file.\n" " package: Package distributions and source code in the " "archives directory.") parser = optparse.OptionParser(usage=usage, description="""Release Nuxeo from a given branch, tag the release, then set the next SNAPSHOT version. If a maintenance version was provided, then a maintenance branch is kept, else it is deleted after release.""") parser.add_option('-r', action="store", type="string", dest='remote_alias', default='origin', help="""the Git alias of remote URL (default: %default)""") parser.add_option('-f', '--final', action="store_true", dest='is_final', default=False, help='is it a final release? (default: %default)') parser.add_option("-b", "--branch", action="store", type="string", help='branch to release (default: current branch)', dest="branch", default="auto") parser.add_option("-t", "--tag", action="store", type="string", dest="tag", default="auto", help="""if final option is True, then the default tag is the current version minus '-SNAPSHOT', else the 'SNAPSHOT' keyword is replaced with a date (aka 'date-based release')""") parser.add_option("-n", "--next", action="store", type="string", dest="next_snapshot", default="auto", help="""next snapshot. If final option is True, then the next snapshot is the current one increased, else it is equal to the current """) parser.add_option('-m', '--maintenance', action="store", dest='maintenance', default="auto", help="""maintenance version (by default, the maintenance branch is deleted after release)""") parser.add_option('-i', '--interactive', action="store_true", dest='interactive', default=False, help="""Not implemented (TODO NXP-8573). Interactive mode.""") parser.add_option('-d', '--deploy', action="store_true", dest='deploy', default=False, help="""deploy artifacts to nightly repository""") parser.add_option('--skipTests', action="store_true", dest='skipTests', default=False, help="""skip tests execution (but compile them)""") (options, args) = parser.parse_args() if len(args) == 1: command = args[0] elif len(args) > 1: raise ExitException(1, "'command' must be a single argument. " "See usage with '-h'.") release_log = os.path.abspath(os.path.join(os.getcwd(), os.pardir, "release.log")) if ("command" in locals() and command == "perform" and os.path.isfile(release_log) and options == parser.get_default_values()): log("Reading parameters from %s ..." % release_log) with open(release_log, "rb") as f: options.remote_alias = f.readline().split("=")[1].strip() options.branch = f.readline().split("=")[1].strip() options.tag = f.readline().split("=")[1].strip() options.next_snapshot = f.readline().split("=")[1].strip() options.maintenance = f.readline().split("=")[1].strip() options.is_final = f.readline().split("=")[1].strip() == "True" options.skipTests = f.readline().split("=")[1].strip() == "True" repo = Repository(os.getcwd(), options.remote_alias) if options.branch == "auto": options.branch = repo.get_current_version() system("git fetch %s" % (options.remote_alias)) repo.git_update(options.branch) release = Release(repo, options.branch, options.tag, options.next_snapshot, options.maintenance, options.is_final, options.skipTests) release.log_summary("command" in locals() and command != "perform") if "command" not in locals(): raise ExitException(1, "Missing command. See usage with '-h'.") elif command == "prepare": release.prepare(options.deploy) elif command == "perform": release.perform() elif command == "package": repo.clone() # workaround for NXBT-121: use install instead of package repo.mvn("clean install", skip_tests=options.skipTests, profiles="qa") release.package_all(release.snapshot) elif command == "test": release.test() else: raise ExitException(1, "Unknown command! See usage with '-h'.") except ExitException, e: if e.message is not None: log("[ERROR] %s" % e.message, sys.stderr) sys.exit(e.return_code)
def perform(self, dryrun=False): """ Perform the release: push source, deploy artifacts and upload packages.""" cwd = os.getcwd() marketplaces_skipped = [] for marketplace in self.get_packages_list(): log("") if self.mp_config.has_option(marketplace, "skip"): log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if not self.mp_config.getboolean(marketplace, "prepared"): log("[WARN] Skipped '%s' (%s)" % (marketplace, "Not prepared")) continue if self.mp_config.getboolean(marketplace, "performed"): log("Skipped '%s' (%s)" % (marketplace, "Already performed")) continue try: if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Perform %s" % marketplace) os.chdir(os.path.join(self.repo.mp_dir, marketplace)) mp_repo = Repository(os.getcwd(), self.alias) # Perform release release_info = ReleaseInfo() release_info.read_release_log( ReleaseInfo.get_release_log(mp_repo.basedir)) mp_release = Release(mp_repo, release_info) mp_release.perform(dryrun=dryrun, upgrade_only=upgrade_only) performed = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) performed = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "performed", str(performed)) self.repo.save_mp_config(self.mp_config) if performed and not upgrade_only: self.upload(CONNECT_PROD_URL, marketplace, dryrun=dryrun)
def prepare(self, dryrun=False): """ Prepare the release.""" cwd = os.getcwd() if not os.path.isdir(self.repo.mp_dir): self.clone() os.chdir(self.repo.mp_dir) marketplaces_skipped = [] for marketplace in self.get_packages_list(): log("") if self.mp_config.has_option(marketplace, "skip"): log("[%s]" % marketplace) log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if self.mp_config.getboolean(marketplace, "prepared"): log("[%s]" % marketplace) log("Skipped '%s' (%s)" % (marketplace, "Already prepared")) continue try: mp_dir = os.path.join(self.repo.mp_dir, marketplace) if not os.path.isdir(mp_dir): os.chdir(self.repo.mp_dir) self.repo.git_pull( marketplace, self.mp_config.get(marketplace, "branch")) else: log("[%s]" % marketplace) os.chdir(mp_dir) mp_repo = Repository(os.getcwd(), self.alias) if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Prepare release of %s..." % marketplace) mp_release = Release( mp_repo, self.mp_config.get(marketplace, "branch"), self.mp_config.get(marketplace, "tag"), self.mp_config.get(marketplace, "next_snapshot"), self.mp_config.get(marketplace, "maintenance_version"), is_final=True, skipTests=self.mp_config.getboolean( marketplace, "skipTests"), skipITs=self.mp_config.getboolean(marketplace, "skipITs"), other_versions=self.mp_config.get(marketplace, "other_versions", None)) mp_release.log_summary() mp_release.prepare(dryrun=dryrun, upgrade_only=upgrade_only, dodeploy=True) prepared = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) prepared = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "prepared", str(prepared)) self.repo.save_mp_config(self.mp_config) if prepared and not upgrade_only: self.upload(CONNECT_TEST_URL, marketplace, dryrun=dryrun)
def prepare(self, dryrun=False): """ Prepare the release.""" cwd = os.getcwd() if not os.path.isdir(self.repo.mp_dir): self.clone() os.chdir(self.repo.mp_dir) marketplaces = self.mp_config.sections() marketplaces_skipped = [] if self.restart_from: idx = marketplaces.index(self.restart_from) marketplaces = marketplaces[idx:] for marketplace in marketplaces: log("") if self.mp_config.has_option(marketplace, "skip"): log("[%s]" % marketplace) log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if self.mp_config.getboolean(marketplace, "prepared"): log("[%s]" % marketplace) log("Skipped '%s' (%s)" % (marketplace, "Already prepared")) continue try: mp_dir = os.path.join(self.repo.mp_dir, marketplace) if not os.path.isdir(mp_dir): os.chdir(self.repo.mp_dir) self.repo.git_pull(marketplace, self.mp_config.get(marketplace, "branch")) else: log("[%s]" % marketplace) os.chdir(mp_dir) mp_repo = Repository(os.getcwd(), self.alias) if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Prepare release of %s..." % marketplace) mp_release = Release(mp_repo, self.mp_config.get(marketplace, "branch"), self.mp_config.get(marketplace, "tag"), self.mp_config.get(marketplace, "next_snapshot"), self.mp_config.get(marketplace, "maintenance_version"), is_final=True, skipTests=False, skipITs=False, other_versions=self.mp_config.get( marketplace, "other_versions", None)) mp_release.log_summary() mp_release.prepare(dryrun=dryrun, upgrade_only=upgrade_only, dodeploy=True) prepared = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) prepared = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "prepared", str(prepared)) self.repo.save_mp_config(self.mp_config) if prepared and not upgrade_only: # Upload on Connect test for dirpath, _, filenames in os.walk(mp_repo.basedir): for name in filenames: path = os.path.join(dirpath, name) if (os.path.isfile(path) and fnmatch.fnmatch(path[len(mp_repo.basedir) + 1:], self.mp_config.get(marketplace, "mp_to_upload"))): self.upload(CONNECT_TEST_URL, path, dryrun=dryrun) self.mp_config.set(marketplace, "uploaded", CONNECT_TEST_URL + ": " + path) self.repo.save_mp_config(self.mp_config)
def main(): assert_git_config() try: usage = ("""usage: %prog <command> [options] %prog clone [-r alias] [-m URL] [-d PATH] %prog branch [-r alias] [-m URL] [-d PATH] [--rf package] [--dryrun] %prog prepare [-r alias] [-m URL] [-d PATH] [--rf package] [--dryrun] %prog perform [-r alias] [-m URL] [-d PATH] [--rf package] [--dryrun] \nCommands: clone: Clone or update Nuxeo Package repositories. branch: Create the release branch so that the branch to release is freed for ongoing development. Following \ 'prepare' or 'perform' commands must use option '--next=done'. If kept, that branch will become the maintenance \ branch after release. prepare: Prepare the release (build, change versions, tag and package source and distributions). The release \ parameters are stored in release-<package name>.log files generated by the release.py script. \ The first call must provide a Nuxeo Packages configuration URL (option '-m') from which a 'release.ini' file is \ generated and will be reused for the next calls. perform: Perform the release (push sources, deploy artifacts and upload packages, tests are always skipped). \ If no parameter is given, they are read from the 'release.ini' file.""") description = """Release Nuxeo Packages.\n You can initiate some parameters with a release log file (option '-d').\n The 'release.ini' file contains informations about the release process:\n - 'prepared = True' if the prepare task succeeded,\n - 'performed = True' if the perform task succeeded,\n - 'uploaded = ...' if an upload successfully happened,\n - 'skip = Failed!' followed by a stack trace in case of error.\n The script can be re-called: it will skip the packages with a skip value and skip the prepare (or perform) if 'prepared = True' (or 'performed = True').\n Failed uploads are not retried and must be manually done.""" help_formatter = IndentedHelpFormatterWithNL( max_help_position=7, width=get_terminal_size()[0]) parser = optparse.OptionParser(usage=usage, description=description, formatter=help_formatter) parser.add_option( '-r', action="store", type="string", dest='remote_alias', default='origin', help="""The Git alias of remote URL. Default: '%default'""") parser.add_option( '-d', "--default", action="store", type="string", dest='default_conf', default=None, help= """The default configuration file (usually '/path/to/release-nuxeo.log'). Default: '%default'""") parser.add_option( '-m', "--marketplace-conf", action="store", type="string", dest='marketplace_conf', default=None, help= """The Nuxeo Packages configuration URL (usually named 'marketplace.ini'). You can use a local file URL ('file://').\n If set to '' (empty string), then it will default to '""" + DEFAULT_MP_CONF_URL + """'. Default: '%default'""") parser.add_option( '-i', '--interactive', action="store_true", dest='interactive', default=False, help= """Not implemented (TODO NXP-8573). Interactive mode. Default: '%default'""" ) parser.add_option( '--rf', '--restart-from', action="store", dest='restart_from', default=None, help="""Restart from a package. Default: '%default'""") parser.add_option('--dryrun', action="store_true", dest='dryrun', default=False, help="""Dry run mode. Default: '%default'""") (options, args) = parser.parse_args() if len(args) == 1: command = args[0] elif len(args) > 1: raise ExitException( 1, "'command' must be a single argument. See usage with '-h'.") full_release = ReleaseMP(options.remote_alias, options.restart_from, options.default_conf, options.marketplace_conf) if "command" not in locals(): raise ExitException(1, "Missing command. See usage with '-h'.") elif command == "clone": full_release.clone() elif command == "branch": full_release.release_branch(dryrun=options.dryrun) elif command == "prepare": full_release.prepare(dryrun=options.dryrun) elif command == "perform": full_release.perform(dryrun=options.dryrun) elif command == "test": full_release.test() else: raise ExitException(1, "Unknown command! See usage with '-h'.") except ExitException, e: if e.message is not None: log("[ERROR] %s" % e.message, sys.stderr) sys.exit(e.return_code)
def perform(self, dryrun=False): """ Perform the release: push source, deploy artifacts and upload packages.""" cwd = os.getcwd() marketplaces_skipped = [] for marketplace in self.get_packages_list(): log("") if self.mp_config.has_option(marketplace, "skip"): log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if not self.mp_config.getboolean(marketplace, "prepared"): log("[WARN] Skipped '%s' (%s)" % (marketplace, "Not prepared")) continue if self.mp_config.getboolean(marketplace, "performed"): log("Skipped '%s' (%s)" % (marketplace, "Already performed")) continue try: if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Perform %s" % marketplace) os.chdir(os.path.join(self.repo.mp_dir, marketplace)) mp_repo = Repository(os.getcwd(), self.alias) # Perform release (_, branch, tag, next_snapshot, maintenance_version, is_final, skipTests, skipITs, _, other_versions, _, _) = Release.read_release_log(mp_repo.basedir) mp_release = Release(mp_repo, branch, tag, next_snapshot, maintenance_version, is_final=is_final, skipTests=skipTests, skipITs=skipITs, other_versions=other_versions) mp_release.perform(dryrun=dryrun, upgrade_only=upgrade_only) performed = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) performed = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "performed", str(performed)) self.repo.save_mp_config(self.mp_config) if performed and not upgrade_only: self.upload(CONNECT_PROD_URL, marketplace, dryrun=dryrun)
def prepare(self, dryrun=False): """ Prepare the release.""" cwd = os.getcwd() if not os.path.isdir(self.repo.mp_dir): self.clone() os.chdir(self.repo.mp_dir) marketplaces_skipped = [] for marketplace in self.get_packages_list(): log("") if self.mp_config.has_option(marketplace, "skip"): log("[%s]" % marketplace) log("[WARN] Skipped '%s' (%s)" % (marketplace, self.mp_config.get(marketplace, "skip"))) marketplaces_skipped.append(marketplace) upgrade_only = True else: upgrade_only = False if self.mp_config.getboolean(marketplace, "prepared"): log("[%s]" % marketplace) log("Skipped '%s' (%s)" % (marketplace, "Already prepared")) continue try: mp_dir = os.path.join(self.repo.mp_dir, marketplace) if not os.path.isdir(mp_dir): os.chdir(self.repo.mp_dir) self.repo.git_pull( marketplace, self.mp_config.get(marketplace, "branch")) else: log("[%s]" % marketplace) os.chdir(mp_dir) mp_repo = Repository(os.getcwd(), self.alias) if upgrade_only: log("Upgrade skipped %s..." % marketplace) else: log("Prepare release of %s..." % marketplace) release_info = ReleaseInfo( module=marketplace, remote_alias=self.alias, branch=self.mp_config.get(marketplace, "branch"), tag=self.mp_config.get(marketplace, "tag"), next_snapshot=self.mp_config.get(marketplace, "next_snapshot"), maintenance_version=self.mp_config.get( marketplace, "maintenance_version"), is_final=self.mp_config.getboolean(marketplace, "is_final"), skip_tests=self.mp_config.getboolean( marketplace, "skipTests"), skip_its=self.mp_config.getboolean(marketplace, "skipITs"), profiles=self.mp_config.get(marketplace, "profiles"), other_versions=self.mp_config.get(marketplace, "other_versions"), #files_pattern, props_pattern, msg_commit, msg_tag, auto_increment_policy=self.mp_config.get( marketplace, "auto_increment_policy"), dryrun=dryrun) mp_release = Release(mp_repo, release_info) release_log = mp_release.log_summary() release_info.read_release_log(release_log) if dryrun: print "DEBUG -- init %s with:" % marketplace for key, value in vars(release_info).iteritems(): if dryrun: print "DEBUG: %s-%s=%s" % (marketplace, key, value) self.mp_config.set("DEFAULT", marketplace + "-" + key, str(value)) if dryrun: print mp_release.prepare(dryrun=dryrun, upgrade_only=upgrade_only, dodeploy=True) prepared = True except Exception, e: stack = traceback.format_exc() if hasattr(e, 'message') and e.message is not None: stack = e.message + "\n" + stack log("[ERROR] %s" % stack) prepared = False stack = stack.replace("%", "%%") self.mp_config.set(marketplace, "skip", "Failed! %s" % stack) self.mp_config.set(marketplace, "prepared", str(prepared)) self.repo.save_mp_config(self.mp_config) if prepared and not upgrade_only: self.upload(CONNECT_TEST_URL, marketplace, dryrun=dryrun)
def main(): assert_git_config() try: usage = ("""usage: %prog <command> [options] %prog clone [-r alias] [-m URL] [-d PATH] %prog branch [-r alias] [-m URL] [-d PATH] [--rf package] [--dryrun] %prog prepare [-r alias] [-m URL] [-d PATH] [--rf package] [--dryrun] %prog perform [-r alias] [-m URL] [-d PATH] [-o owner] [--rf package] [--dryrun] \nCommands: clone: Clone or update Nuxeo Package repositories. branch: Create the release branch so that the branch to release is freed for ongoing development. Following \ 'prepare' or 'perform' commands must use option '--next=done'. If kept, that branch will become the maintenance \ branch after release. prepare: Prepare the release (build, change versions, tag and package source and distributions). The release \ parameters are stored in release-<package name>.log files generated by the release.py script. \ The first call must provide a Nuxeo Packages configuration URL (option '-m') from which a 'release.ini' file is \ generated and will be reused for the next calls. perform: Perform the release (push sources, deploy artifacts and upload packages, tests are always skipped). \ If no parameter is given, they are read from the 'release.ini' file.""") description = """Release Nuxeo Packages.\n You can initiate some parameters with a release log file (option '-d').\n The 'release.ini' file contains informations about the release process:\n - 'prepared = True' if the prepare task succeeded,\n - 'performed = True' if the perform task succeeded,\n - 'uploaded = ...' if an upload successfully happened,\n - 'skip = Failed!' followed by a stack trace in case of error.\n The script can be re-called: it will skip the packages with a skip value and skip the prepare (or perform) if 'prepared = True' (or 'performed = True').\n Failed uploads are not retried and must be manually done.""" help_formatter = IndentedHelpFormatterWithNL(max_help_position=7, width=get_terminal_size()[0]) parser = optparse.OptionParser(usage=usage, description=description, formatter=help_formatter) parser.add_option('-r', action="store", type="string", dest='remote_alias', default='origin', help="""The Git alias of remote URL. Default: '%default'""") parser.add_option('-d', "--default", action="store", type="string", dest='default_conf', default=None, help="""The default configuration file (usually '/path/to/release-nuxeo.log'). Default: '%default'""") parser.add_option('-m', "--marketplace-conf", action="store", type="string", dest='marketplace_conf', default=None, help="""The Nuxeo Packages configuration URL (usually named 'marketplace.ini'). You can use a local file URL ('file://').\n If set to '' (empty string), then it will default to '""" + DEFAULT_MP_CONF_URL + """'. Default: '%default'""") parser.add_option('-o', "--owner", action="store", type="string", dest='owner', default=None, help="""The Nuxeo Package owner, if the package is private. This is the id of the connect client document on Connect. Sample value: 45a78af-7f83-44b2-79e1-f102abf7e435.""") parser.add_option('-i', '--interactive', action="store_true", dest='interactive', default=False, help="""Not implemented (TODO NXP-8573). Interactive mode. Default: '%default'""") parser.add_option('--rf', '--restart-from', action="store", dest='restart_from', default=None, help="""Restart from a package. Default: '%default'""") parser.add_option('--dryrun', action="store_true", dest='dryrun', default=False, help="""Dry run mode. Default: '%default'""") (options, args) = parser.parse_args() if len(args) == 1: command = args[0] elif len(args) > 1: raise ExitException(1, "'command' must be a single argument. See usage with '-h'.") full_release = ReleaseMP(options.remote_alias, options.restart_from, options.default_conf, options.marketplace_conf) if "command" not in locals(): raise ExitException(1, "Missing command. See usage with '-h'.") elif command == "clone": full_release.clone() elif command == "branch": full_release.release_branch(dryrun=options.dryrun) elif command == "prepare": full_release.prepare(dryrun=options.dryrun) elif command == "perform": full_release.perform(dryrun=options.dryrun) elif command == "test": full_release.test() else: raise ExitException(1, "Unknown command! See usage with '-h'.") except ExitException, e: if e.message is not None: log("[ERROR] %s" % e.message, sys.stderr) sys.exit(e.return_code)