Search in sources :

Example 1 with BuildException

use of eu.bcvsolutions.idm.tool.exception.BuildException in project CzechIdMng by bcvsolutions.

the class ConsoleRunner method run.

@Override
public void run(String... args) throws ParseException, IOException {
    // 
    // available commands
    Option optionVersion = Option.builder("v").longOpt("version").desc("print tool version.").build();
    Option optionHelp = Option.builder("h").longOpt("help").desc("print this message.").build();
    Option optionBuild = Option.builder().longOpt("build").desc("Build project or build product only (under current develop version in develop branch).\n" + "Maven 'install' command is used for product build, artifact will be installed into the local maven repository (=> usable as dependency for other module).\n" + "Use '-p' argument to project build.").build();
    Option optionRelease = Option.builder().longOpt("release").desc("Release product or module under '--release-version' argument. New development version will be set as '--develop-version' argument.").build();
    Option optionPublish = Option.builder().longOpt("publish").desc("Push prepared development, production and tags into origin repository.").build();
    Option optionReleaseAndPublish = Option.builder().longOpt("release-publish").desc("Release and publish shortcut as one command, taking the same arguments as '--release' command.").build();
    Option optionGetVersion = Option.builder().longOpt("get-version").desc("Get current product version (on the development branch or set '--development-branch' argument).").build();
    Option optionSetVersion = Option.builder().longOpt("set-version").desc("Set current product version (on the development branch - development branch can be changed only).").build();
    Option optionRevertVersion = Option.builder().longOpt("revert-version").desc("Changed versions by release command can be reverted if needed (before commit, usable after change product version only).").build();
    // 
    // product root
    Option optionRepositoryLocation = Option.builder("r").longOpt("repository-location").desc("Repository root folder - should contain all modules (<repository-location>/Realization/...).\n" + "Folder 'CzechIdMng' in the same folder as idm-tool.jar will be used as default for product.\n" + "Folder '<module>' in the same folder as idm-tool.jar will be used as default for module.\n").argName("path").hasArg().build();
    // 
    // optional arguments
    Option optionMavenHome = Option.builder().required(false).longOpt("maven-home").desc("Maven home directory.\n" + "MAVEN_HOME system property will be used as default.\n" + "Maven directory should contain command <maven-home>/bin/mvn.").argName("path").hasArg().build();
    Option optionNodeHome = Option.builder().required(false).longOpt("node-home").desc("Node home directory.\n" + "Global node instalation directory should contain executable node command.\n" + "Node and npm will be dowloaded and installed localy automaticaly into tool target folder (<target>/npm) by default otherwise.\n" + "For Windows <node-home>/node/node.exe.\n" + "For Linux <node-home>/node").argName("path").hasArg().build();
    Option optionDevelopBranch = Option.builder().required(false).longOpt("develop-branch").desc("Branch with feature - working branch.\n" + "'develop' will be used as default.").argName("branchName").hasArg().build();
    Option optionMasterBranch = Option.builder().required(false).longOpt("master-branch").desc("Branch for releases - where feature has to be merged after release.\n" + "'master' will be used as default.\n" + "'none' can be given - merge don't be executed (e.g. when some old hotfix branch is released).\n").argName("masterBranch").hasArg().build();
    Option optionReleaseVersion = Option.builder().required(false).longOpt("release-version").desc("Usable with '--release' command. Release will be create under this version.\n" + "Stable semantic version will be used as default (=> current no snapshot version).").argName("version").hasArg().build();
    Option optionDevelopVersion = Option.builder().required(false).longOpt("develop-version").desc("Usable with '--release' command. After release this version will be used in development branch.\n" + "Next minor snapshot semantic version will be used as default (=> current minor snapshot version + 1).\n" + "See major, minor, patch, hotfix argument if different version is needed.").argName("snapshot version").hasArg().build();
    Option optionUsername = Option.builder().required(false).longOpt("username").desc("Git username, if https repitory is used. When ssh repository is used, then passphrase for ssh key is needed only.").argName("git username").hasArg().build();
    Option optionPassword = Option.builder().required(false).longOpt("password").desc("If ssh repository is used / cloned, then passphrase for ssh key is needed only.\n" + "If https repository is used / cloned, then git username and password is needed.\n" + "If two-factor authentication is enabled for <username>, " + "then token has to be given (see git documentation, how to generate authentication token for developers).\n" + "If ssh key is used, then put passphrase for ssh key (It loads the known hosts and private keys from their " + "default locations (identity, id_rsa and id_dsa) in the user .ssh directory.).").argName("git password / token / ssh passphrase").hasArg().build();
    // 
    // module switch
    Option optionModule = Option.builder("m").required(false).longOpt("module").desc("Switch to module release / build.").argName("moduleId").hasArg().build();
    // 
    // project switch
    Option optionProject = Option.builder("p").required(false).longOpt("project").desc("Switch to project build.").build();
    // 
    // force commit / changes is not checked
    Option optionForce = Option.builder().required(false).longOpt("force").desc(String.format("Count of files changed by release command will not be checked. Limit of changed files is [%s].", ReleaseManager.MAX_RELEASE_CHANGES)).build();
    // major / minor / patch / hotfix
    Option optionMajor = Option.builder().required(false).longOpt("major").desc("Next develop version will be major, e.g. release 1.2.3 => develop 2.0.0-SNAPSHOT.").build();
    Option optionMinor = Option.builder().required(false).longOpt("minor").desc("Next develop version will be minor, e.g. release 1.2.3 => develop 1.3.0-SNAPSHOT. Will be applied as default.").build();
    Option optionPatch = Option.builder().required(false).longOpt("patch").desc("Next develop version will be patch, e.g. release 1.2.3 => develop 1.2.4-SNAPSHOT.").build();
    Option optionHotfix = Option.builder().required(false).longOpt("hotfix").desc("Next develop version will be hotfix, e.g. release 1.2.3 => develop 1.2.3.1-SNAPSHOT.").build();
    Option optionClean = Option.builder("c").required(false).longOpt("clean").desc("Clean up dowloaded frontend libraries in node_modules.").build();
    Option optionResolveDependencies = Option.builder().required(false).longOpt("resolve-dependencies").desc("Third party module dependencies will be resolved automatically (not resolved by default), when project is built.\n" + "Dependencies will not be resolved and included in build, if feature is not enabled => \n" + "all module dependencies has to be installed manually (prepared ~ copied in 'modules' folder).\n" + "Parameter is available for build a project only.").build();
    Option optionSkipFrontendBuild = Option.builder().required(false).longOpt("skip-frontend-build").desc("Frontend build will be skipped - product provided frontend will be used for build distribution artifacts.\n" + "Parameter is available for build a project only.").build();
    Options options = new Options();
    // 
    // available commands
    OptionGroup commandGroup = new OptionGroup();
    commandGroup.setRequired(true);
    commandGroup.addOption(optionVersion);
    commandGroup.addOption(optionHelp);
    commandGroup.addOption(optionBuild);
    commandGroup.addOption(optionRelease);
    commandGroup.addOption(optionPublish);
    commandGroup.addOption(optionReleaseAndPublish);
    commandGroup.addOption(optionSetVersion);
    commandGroup.addOption(optionGetVersion);
    commandGroup.addOption(optionRevertVersion);
    options.addOptionGroup(commandGroup);
    // 
    options.addOption(optionRepositoryLocation);
    options.addOption(optionMavenHome);
    options.addOption(optionNodeHome);
    options.addOption(optionDevelopBranch);
    options.addOption(optionMasterBranch);
    options.addOption(optionReleaseVersion);
    options.addOption(optionDevelopVersion);
    options.addOption(optionUsername);
    options.addOption(optionPassword);
    options.addOption(optionModule);
    options.addOption(optionProject);
    options.addOption(optionForce);
    options.addOption(optionMajor);
    options.addOption(optionMinor);
    options.addOption(optionPatch);
    options.addOption(optionHotfix);
    options.addOption(optionClean);
    options.addOption(optionResolveDependencies);
    options.addOption(optionSkipFrontendBuild);
    // 
    // parse arguments
    CommandLineParser parser = new DefaultParser();
    CommandLine commandLine = parser.parse(options, args, false);
    // log given arguments (for bug report, without password value)
    List<String> arguments = Arrays.stream(commandLine.getOptions()).map(option -> {
        if (!option.hasArg()) {
            return option.getLongOpt();
        }
        return String.format("%s=%s", option.getLongOpt(), // prevent to print password into logs
        option.getLongOpt().equals(optionPassword.getLongOpt()) ? GuardedString.SECRED_PROXY_STRING : option.getValue());
    }).collect(Collectors.toList());
    LOG.info("Running tool with arguments {}.", arguments);
    // 
    boolean projectBuild = commandLine.hasOption(optionProject.getLongOpt());
    boolean releaseModule = commandLine.hasOption(optionModule.getLongOpt());
    // 
    if (productReleaseManager == null) {
        // Product manager will be inited by default
        // manager's methods are used by console runner
        productReleaseManager = new ProductReleaseManager();
    }
    if (releaseModule && !projectBuild && moduleReleaseManager == null) {
        moduleReleaseManager = new ModuleReleaseManager(commandLine.getOptionValue(optionModule.getLongOpt()));
    }
    // 
    if (commandLine.hasOption(optionVersion.getLongOpt())) {
        System.out.println(String.format("v%s", getVersion()));
        return;
    }
    // 
    if (commandLine.hasOption(optionHelp.getLongOpt())) {
        printHelp(options);
        return;
    }
    // 
    String rootFolder = null;
    if (commandLine.hasOption(optionRepositoryLocation.getLongOpt())) {
        rootFolder = commandLine.getOptionValue(optionRepositoryLocation.getLongOpt());
    }
    // 
    String mavenHome = null;
    if (commandLine.hasOption(optionMavenHome.getLongOpt())) {
        mavenHome = commandLine.getOptionValue(optionMavenHome.getLongOpt());
    }
    String nodeHome = null;
    if (commandLine.hasOption(optionNodeHome.getLongOpt())) {
        nodeHome = commandLine.getOptionValue(optionNodeHome.getLongOpt());
    }
    // 
    if (projectBuild) {
        if (!commandLine.hasOption(optionBuild.getLongOpt())) {
            throw new BuildException("Build a project is supported only.");
        }
        boolean clean = commandLine.hasOption(optionClean.getLongOpt());
        boolean resolveDependencies = commandLine.hasOption(optionResolveDependencies.getLongOpt());
        boolean skipFrontendBuild = commandLine.hasOption(optionSkipFrontendBuild.getLongOpt());
        // 
        if (projectManager == null) {
            projectManager = new ProjectManager();
            projectManager.setMavenHome(mavenHome);
            projectManager.setNodeHome(nodeHome);
            projectManager.setResolveDependencies(resolveDependencies);
            projectManager.setSkipFrontendBuild(skipFrontendBuild);
            projectManager.init();
        }
        // /tool folder by default => project is in parent folder.
        projectManager.build(rootFolder == null ? "../" : rootFolder, clean);
        // 
        LOG.info("Complete!");
        return;
    }
    // 
    // Release
    ReleaseManager releaseManager = getReleaseManager(releaseModule);
    releaseManager.setMavenHome(mavenHome);
    // 
    if (commandLine.hasOption(optionRepositoryLocation.getLongOpt())) {
        releaseManager.setRepositoryRoot(commandLine.getOptionValue(optionRepositoryLocation.getLongOpt()));
    }
    if (commandLine.hasOption(optionDevelopBranch.getLongOpt())) {
        releaseManager.setDevelopBranch(commandLine.getOptionValue(optionDevelopBranch.getLongOpt()));
        LOG.debug("Using develop branch [{}].", releaseManager.getDevelopBranch());
    }
    if (commandLine.hasOption(optionMasterBranch.getLongOpt())) {
        String masterBranch = commandLine.getOptionValue(optionMasterBranch.getLongOpt());
        if (masterBranch.equals("none")) {
            masterBranch = null;
        }
        releaseManager.setMasterBranch(masterBranch);
        LOG.debug("Using production branch [{}].", releaseManager.getMasterBranch());
    }
    if (commandLine.hasOption(optionUsername.getLongOpt())) {
        String username = commandLine.getOptionValue(optionUsername.getLongOpt());
        releaseManager.setUsername(username);
        LOG.debug("Using git username [{}].", username);
    }
    // 
    GuardedString password = null;
    if (commandLine.hasOption(optionPassword.getLongOpt())) {
        password = new GuardedString(commandLine.getOptionValue(optionPassword.getLongOpt()));
    } else {
        // get password from file
        String externalPassword = getProperty(PROPERTY_PASSWORD);
        if (StringUtils.isNotEmpty(externalPassword)) {
            password = new GuardedString(externalPassword);
        } else if (commandLine.hasOption(optionRelease.getLongOpt()) || commandLine.hasOption(optionReleaseAndPublish.getLongOpt())) {
            // prompt when publish / release-publish command is used
            // creates a console object
            Console cnsl = System.console();
            if (cnsl != null) {
                System.out.println(optionPassword.getDescription());
                char[] pwd = cnsl.readPassword(String.format("%s: ", optionPassword.getArgName()));
                if (pwd != null && pwd.length > 0) {
                    password = new GuardedString(new String(pwd));
                }
            }
        }
    }
    if (password != null) {
        releaseManager.setPassword(password);
        LOG.info(String.format("Password (%s) is given.", optionPassword.getArgName()));
    }
    // 
    if (commandLine.hasOption(optionForce.getLongOpt())) {
        releaseManager.setForce(true);
        LOG.debug("Force argument was given, count of files changed by release command will not be checked.");
    }
    // before run - check props is set
    releaseManager.init();
    // 
    if (commandLine.hasOption(optionBuild.getLongOpt())) {
        String currentVersion = releaseManager.build();
        // 
        LOG.info("Product version [{}] successfully built and installed into local maven repository.", currentVersion);
    } else if (commandLine.hasOption(optionRelease.getLongOpt()) || commandLine.hasOption(optionReleaseAndPublish.getLongOpt())) {
        String releaseVersion = commandLine.getOptionValue(optionReleaseVersion.getLongOpt());
        String developVersion = commandLine.getOptionValue(optionDevelopVersion.getLongOpt());
        // current [snapshot] develop version
        String currentVersion = releaseManager.getCurrentVersion(null);
        // 
        if (StringUtils.isEmpty(developVersion)) {
            // prepare next development version by major / minor / patch / hotfix switch
            ReleaseManager.VersionType versionType = null;
            if (commandLine.hasOption(optionMajor.getLongOpt())) {
                versionType = ReleaseManager.VersionType.MAJOR;
            }
            if (commandLine.hasOption(optionMinor.getLongOpt())) {
                versionType = ReleaseManager.VersionType.MINOR;
            }
            if (commandLine.hasOption(optionPatch.getLongOpt())) {
                versionType = ReleaseManager.VersionType.PATCH;
            }
            if (commandLine.hasOption(optionHotfix.getLongOpt())) {
                versionType = ReleaseManager.VersionType.HOTFIX;
            }
            // 
            if (versionType == null) {
                // minor as default
                versionType = ReleaseManager.VersionType.MINOR;
            }
            developVersion = releaseManager.getNextSnapshotVersionNumber(StringUtils.isEmpty(releaseVersion) ? currentVersion : releaseVersion, versionType);
        }
        // 
        String releasedVersion = releaseManager.release(releaseVersion, developVersion);
        // 
        LOG.info("Product version released [{}]. New development version [{}].", releasedVersion, currentVersion);
        LOG.info("Branches [{}], [{}] and tag [{}] are prepared to push into origin (use --publish command).", releaseManager.getDevelopBranch(), releaseManager.getMasterBranch(), releasedVersion);
        // publish shortcut after release
        if (commandLine.hasOption(optionReleaseAndPublish.getLongOpt())) {
            releaseManager.publish();
            LOG.info("Branches [{}], [{}] and prepared tags pushed into origin.", releaseManager.getDevelopBranch(), releaseManager.getMasterBranch());
        }
    } else if (commandLine.hasOption(optionPublish.getLongOpt())) {
        // standalone publish
        releaseManager.publish();
        LOG.info("Branches [{}], [{}] and prepared tags pushed into origin.", releaseManager.getDevelopBranch(), releaseManager.getMasterBranch());
    } else if (commandLine.hasOption(optionRevertVersion.getLongOpt())) {
        LOG.info("Current product version [{}].", releaseManager.revertVersion());
    } else if (commandLine.hasOption(optionSetVersion.getLongOpt())) {
        String developVersion = commandLine.getOptionValue(optionDevelopVersion.getLongOpt());
        // 
        LOG.info("Current product version [{}].", releaseManager.setVersion(developVersion));
    } else if (commandLine.hasOption(optionGetVersion.getLongOpt())) {
        String branch = null;
        if (commandLine.hasOption(optionDevelopBranch.getLongOpt())) {
            branch = commandLine.getOptionValue(optionDevelopBranch.getLongOpt());
        }
        String currentVersion = releaseManager.getCurrentVersion(branch);
        // 
        LOG.info("Current product version [{}].", currentVersion);
    }
    // 
    LOG.info("Complete!");
}
Also used : Arrays(java.util.Arrays) Options(org.apache.commons.cli.Options) Autowired(org.springframework.beans.factory.annotation.Autowired) HelpFormatter(org.apache.commons.cli.HelpFormatter) StringUtils(org.apache.commons.lang3.StringUtils) ProductReleaseManager(eu.bcvsolutions.idm.tool.service.impl.ProductReleaseManager) DefaultParser(org.apache.commons.cli.DefaultParser) ResultCodeException(eu.bcvsolutions.idm.core.api.exception.ResultCodeException) CommandLine(org.apache.commons.cli.CommandLine) Console(java.io.Console) CommandLineRunner(org.springframework.boot.CommandLineRunner) Option(org.apache.commons.cli.Option) ReleaseManager(eu.bcvsolutions.idm.tool.service.api.ReleaseManager) Properties(java.util.Properties) CommandLineParser(org.apache.commons.cli.CommandLineParser) ProjectManager(eu.bcvsolutions.idm.tool.service.impl.ProjectManager) IOException(java.io.IOException) ModuleReleaseManager(eu.bcvsolutions.idm.tool.service.impl.ModuleReleaseManager) FileInputStream(java.io.FileInputStream) Collectors(java.util.stream.Collectors) File(java.io.File) List(java.util.List) ParseException(org.apache.commons.cli.ParseException) OptionGroup(org.apache.commons.cli.OptionGroup) GuardedString(eu.bcvsolutions.idm.core.security.api.domain.GuardedString) InputStream(java.io.InputStream) BuildException(eu.bcvsolutions.idm.tool.exception.BuildException) Options(org.apache.commons.cli.Options) GuardedString(eu.bcvsolutions.idm.core.security.api.domain.GuardedString) ModuleReleaseManager(eu.bcvsolutions.idm.tool.service.impl.ModuleReleaseManager) GuardedString(eu.bcvsolutions.idm.core.security.api.domain.GuardedString) ProjectManager(eu.bcvsolutions.idm.tool.service.impl.ProjectManager) ProductReleaseManager(eu.bcvsolutions.idm.tool.service.impl.ProductReleaseManager) CommandLine(org.apache.commons.cli.CommandLine) OptionGroup(org.apache.commons.cli.OptionGroup) ProductReleaseManager(eu.bcvsolutions.idm.tool.service.impl.ProductReleaseManager) ReleaseManager(eu.bcvsolutions.idm.tool.service.api.ReleaseManager) ModuleReleaseManager(eu.bcvsolutions.idm.tool.service.impl.ModuleReleaseManager) Console(java.io.Console) Option(org.apache.commons.cli.Option) CommandLineParser(org.apache.commons.cli.CommandLineParser) BuildException(eu.bcvsolutions.idm.tool.exception.BuildException) DefaultParser(org.apache.commons.cli.DefaultParser)

Example 2 with BuildException

use of eu.bcvsolutions.idm.tool.exception.BuildException in project CzechIdMng by bcvsolutions.

the class ProjectManager method prepareBackendMavenProject.

private void prepareBackendMavenProject(File extractedProductFolder, String productVersion, List<File> installedJarModules, File targetFolder) throws Exception {
    File projectDescriptor = new File(targetFolder, "pom.xml");
    // 
    FileUtils.copyInputStreamToFile(new ClassPathResource("eu/bcvsolutions/idm/build/war-pom.xml").getInputStream(), projectDescriptor);
    if (installedJarModules.isEmpty()) {
        return;
    }
    if (!resolveDependencies) {
        LOG.warn("Resolve and install third party dependencies is disabled. " + "Dependencies will not be included in build - all module dependencies has to be installed manually (copied in 'modules' folder).");
        return;
    }
    // append registered backend modules as dependencies => third party module libraries will be resolved by maven automatically
    // 
    // parse xml and append modules as standard maven dependencies
    // TODO: can be refactored to maven model usage ...
    XmlMapper xmlMapper = new XmlMapper();
    xmlMapper.configure(SerializationFeature.WRAP_ROOT_VALUE, false);
    xmlMapper.configure(DeserializationFeature.UNWRAP_ROOT_VALUE, false);
    xmlMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
    xmlMapper.configure(ToXmlGenerator.Feature.WRITE_XML_DECLARATION, true);
    xmlMapper.enable(SerializationFeature.INDENT_OUTPUT);
    // 
    ObjectNode buildPom = (ObjectNode) xmlMapper.readTree(projectDescriptor);
    // 
    // set parent to include CzechIdM dependencies
    ObjectNode parentWrapper = xmlMapper.createObjectNode();
    parentWrapper.put("groupId", ReleaseManager.MAVEN_GROUP_ID);
    parentWrapper.put("artifactId", "idm-parent");
    parentWrapper.put("version", productVersion);
    buildPom.set("parent", parentWrapper);
    // 
    // try install parent into local repository
    File parentProjectDescriptor = new File(String.format("%s/META-INF/maven/eu.bcvsolutions.idm/idm-parent/pom.xml", extractedProductFolder.getPath()));
    if (parentProjectDescriptor.exists()) {
        Model parentModel = mavenManager.installFile(parentProjectDescriptor, null);
        // 
        if (parentModel != null) {
            LOG.info("Product parent project [{}] installed into local maven repository for backend build.", parentProjectDescriptor.getPath());
        } else {
            LOG.warn("Product parent project [{}] not installed into local maven repository for backend build.", parentProjectDescriptor.getPath());
        }
    // FIXME: code bellow work partially only => "pom"s (e.g. idm-core) ~ sub parents are not available in war (same as parent above)
    // install all product (~private) dependencies into local repository
    // File warLibs = new File(String.format("%s/WEB-INF/lib", extractedProductFolder.getPath()));
    // for (File file : FileUtils.listFiles(warLibs, null, true)) {
    // if (file.getName().startsWith("idm-")) {
    // // extract product module and get pom file
    // File extractedModuleFolder = new File(targetFolder, FilenameUtils.removeExtension(file.getName()));
    // ZipUtils.extract(file, extractedModuleFolder.getPath());
    // Model model = mavenManager.getModel(extractedModuleFolder);
    // mavenManager.installFile(model.getPomFile(), file);
    // }
    // }
    }
    // 
    // 
    // find pom.xml modules in jar
    Map<String, String> resolvedModules = new HashMap<>(ProductReleaseManager.BACKEND_MODULES.length + installedJarModules.size());
    // add all product modules as resolved => will not be registered repetitivelly
    Arrays.stream(ProductReleaseManager.BACKEND_MODULES).map(backendModule -> {
        // transform path to module to artefact id by conventions
        String productArtefactId = backendModule;
        int slashPosition = productArtefactId.lastIndexOf('/');
        if (slashPosition > 0) {
            // not at start => >
            productArtefactId = productArtefactId.substring(slashPosition + 1);
        }
        productArtefactId = String.format("idm-%s", productArtefactId);
        // 
        return getSimpleModuleId(ReleaseManager.MAVEN_GROUP_ID, productArtefactId);
    }).forEach(productModuleId -> {
        resolvedModules.put(productModuleId, "");
    });
    // 
    Map<String, Model> modules = new LinkedHashMap<>();
    for (File installedJarModule : installedJarModules) {
        // extract and install maven module
        File extractedModuleFolder = new File(targetFolder, FilenameUtils.removeExtension(installedJarModule.getName()));
        if (extractedModuleFolder.exists()) {
            Model model = mavenManager.getModel(extractedModuleFolder);
            if (model != null) {
                modules.put(model.getId(), model);
            // 
            // FIXME: code bellow work partially only => "pom"s (e.g. idm-crt, idm-scim) ~ sub parents are not available in war (same as parent above)
            // mavenManager.installFile(model.getPomFile(), installedJarModule);
            }
        }
    }
    // a module doesn't contain pom descriptor
    if (modules.isEmpty()) {
        return;
    }
    // append installed modules as dependencies
    int registeredDependencies = 0;
    ArrayNode dependencies = xmlMapper.createArrayNode();
    for (Model module : modules.values()) {
        String groupId = mavenManager.getGroupId(module);
        String artifactId = module.getArtifactId();
        String simpleModuleId = getSimpleModuleId(groupId, artifactId);
        String version = mavenManager.getVersion(module);
        // simple check dependency is fully specified
        if (StringUtils.isEmpty(groupId) || StringUtils.isEmpty(artifactId) || StringUtils.isEmpty(version)) {
            throw new BuildException(String.format("Backend module artefact [%s:%s:%s] cannot " + "be registered as maven dependency for backend build, " + "required artefact properties are not defined.", groupId, artifactId, version));
        }
        // skip already resolved modules
        if (resolvedModules.containsKey(simpleModuleId)) {
            String checkVersion = resolvedModules.get(simpleModuleId);
            if (StringUtils.isEmpty(checkVersion)) {
                LOG.debug("Module [{}] is already registered, skipping.", simpleModuleId);
                continue;
            }
            if (checkVersion.equals(version)) {
                LOG.debug("Module [{}] is already registered with the same version [{}], skipping.", simpleModuleId, checkVersion);
                continue;
            }
            throw new BuildException(String.format("Backend module artefact [%s:%s:%s] cannot " + "be registered as maven dependency for backend build, " + "the same library is already registeres with version [%s]. " + "Update module dependencies or copy third party library to modules folder to ensure concrete version is used.", groupId, artifactId, version, checkVersion));
        }
        // 
        // create target dependency
        ObjectNode targetDependency = xmlMapper.createObjectNode();
        targetDependency.put("groupId", groupId);
        targetDependency.put("artifactId", artifactId);
        targetDependency.put("version", version);
        dependencies.add(targetDependency);
        // 
        registeredDependencies++;
        resolvedModules.put(simpleModuleId, version);
        LOG.info("Backend module artefact [{}:{}:{}] registered as maven dependency for backend build.", groupId, artifactId, version);
    }
    // no additional 3th party dependencies are resolved
    if (registeredDependencies == 0) {
        return;
    }
    // 
    // add core module as dependency => all product librarioes will be resolved at first
    ObjectNode coreDependency = xmlMapper.createObjectNode();
    coreDependency.put("groupId", ReleaseManager.MAVEN_GROUP_ID);
    coreDependency.put("artifactId", "idm-core-impl");
    coreDependency.put("version", productVersion);
    // the first dependency
    dependencies.insert(0, coreDependency);
    // 
    ObjectNode dependenciesWrapper = xmlMapper.createObjectNode();
    dependenciesWrapper.set("dependency", dependencies);
    buildPom.set("dependencies", dependenciesWrapper);
    // 
    try (FileOutputStream outputStream = new FileOutputStream(projectDescriptor)) {
        JsonGenerator jGenerator = xmlMapper.getFactory().createGenerator(outputStream, JsonEncoding.UTF8);
        xmlMapper.writerWithDefaultPrettyPrinter().withRootName("project").writeValue(jGenerator, buildPom);
        jGenerator.close();
    }
    LOG.info("Backend maven project [{}] for build prepared. Modules [{}] registered as dependency.", projectDescriptor.getPath(), registeredDependencies);
}
Also used : Manifest(java.util.jar.Manifest) Arrays(java.util.Arrays) JsonGenerator(com.fasterxml.jackson.core.JsonGenerator) AttachableEntity(eu.bcvsolutions.idm.core.ecm.api.entity.AttachableEntity) XmlMapper(com.fasterxml.jackson.dataformat.xml.XmlMapper) ClassPathResource(org.springframework.core.io.ClassPathResource) ToXmlGenerator(com.fasterxml.jackson.dataformat.xml.ser.ToXmlGenerator) HashMap(java.util.HashMap) StringUtils(org.apache.commons.lang3.StringUtils) DeserializationFeature(com.fasterxml.jackson.databind.DeserializationFeature) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) ArrayList(java.util.ArrayList) LinkedHashMap(java.util.LinkedHashMap) JsonEncoding(com.fasterxml.jackson.core.JsonEncoding) Service(org.springframework.stereotype.Service) Map(java.util.Map) JsonNode(com.fasterxml.jackson.databind.JsonNode) ReleaseManager(eu.bcvsolutions.idm.tool.service.api.ReleaseManager) ZipException(java.util.zip.ZipException) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper) FileOutputStream(java.io.FileOutputStream) IOException(java.io.IOException) FileUtils(org.apache.commons.io.FileUtils) FileInputStream(java.io.FileInputStream) Collectors(java.util.stream.Collectors) Maps(com.google.common.collect.Maps) File(java.io.File) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) IOUtils(org.apache.commons.io.IOUtils) List(java.util.List) SerializationFeature(com.fasterxml.jackson.databind.SerializationFeature) ZipUtils(eu.bcvsolutions.idm.core.api.utils.ZipUtils) FilenameUtils(org.apache.commons.io.FilenameUtils) InputStream(java.io.InputStream) Model(org.apache.maven.model.Model) Assert(org.springframework.util.Assert) BuildException(eu.bcvsolutions.idm.tool.exception.BuildException) ObjectNode(com.fasterxml.jackson.databind.node.ObjectNode) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) ClassPathResource(org.springframework.core.io.ClassPathResource) XmlMapper(com.fasterxml.jackson.dataformat.xml.XmlMapper) LinkedHashMap(java.util.LinkedHashMap) FileOutputStream(java.io.FileOutputStream) Model(org.apache.maven.model.Model) JsonGenerator(com.fasterxml.jackson.core.JsonGenerator) ArrayNode(com.fasterxml.jackson.databind.node.ArrayNode) BuildException(eu.bcvsolutions.idm.tool.exception.BuildException) File(java.io.File)

Example 3 with BuildException

use of eu.bcvsolutions.idm.tool.exception.BuildException in project CzechIdMng by bcvsolutions.

the class ProjectManager method build.

/**
 * Build project.
 *
 * @param rootPath
 * @return true - project artifacts are available in dist directory
 */
public boolean build(String rootPath, boolean clean) {
    try {
        Assert.notNull(mavenManager, "Maven manager is not inited. Init manager before usage.");
        Assert.notNull(rootPath, "Path to folder with product and modules is required.");
        // 
        File rootFolder = new File(rootPath);
        Assert.isTrue(rootFolder.exists(), String.format("Root folder [%s] not found.", rootPath));
        File productFolder = new File(rootFolder, "product");
        Assert.isTrue(productFolder.exists(), String.format("Product folder [%s] not found.", productFolder));
        File modulesFolder = new File(rootFolder, "modules");
        File frontendFolder = new File(rootFolder, "frontend");
        File targetFolder = new File(rootFolder, "target");
        File distFolder = new File(rootFolder, "dist");
        // 
        LOG.info("Clean previous target and distribution ...");
        if (clean) {
            LOG.info("Previously installed / used frontend nodejs, npm and node_modules will be deleted ...");
        }
        // clean previous target and dist
        if (targetFolder.exists()) {
            // cleanup content, which can be copied
            for (File file : targetFolder.listFiles()) {
                // prevent to delete node_modules, if clean is not used
                if (clean) {
                    FileUtils.forceDelete(file);
                } else if ("npm".equals(file.getName())) {
                // nothing - leave installed npm
                } else if ("frontend".equals(file.getName())) {
                    for (File frontendFile : file.listFiles()) {
                        if ("node_modules".equals(frontendFile.getName())) {
                        // nothing
                        } else {
                            FileUtils.forceDelete(frontendFile);
                        }
                    }
                } else {
                    FileUtils.forceDelete(file);
                }
            }
        } else {
            targetFolder.mkdirs();
        }
        if (distFolder.exists()) {
            // cleanup all content from dist folder
            for (File file : distFolder.listFiles()) {
                FileUtils.forceDelete(file);
            }
        } else {
            distFolder.mkdirs();
        }
        // 
        // resolve product artefact
        File extractedProductFolder = new File(targetFolder, "war");
        // 
        // check product version in product folder
        String productVersion = getVersion(productFolder);
        if (StringUtils.isNotEmpty(productVersion)) {
            // extracted product
            FileUtils.copyDirectory(productFolder, extractedProductFolder);
            LOG.info("Extracted product [{}] found directly in product folder.", productFolder.getPath());
        } else {
            for (File file : productFolder.listFiles()) {
                // TODO: extracted product higher priority?
                if (file.isDirectory()) {
                    productVersion = getVersion(file);
                    if (StringUtils.isNotEmpty(productVersion)) {
                        // extracted product => just copy in this case
                        FileUtils.copyDirectory(file, extractedProductFolder);
                        LOG.info("Extracted product folder [{}] found.", file.getPath());
                        // 
                        break;
                    }
                }
                if (file.getName().endsWith(".war")) {
                    // .war artefact
                    File productWar = file;
                    LOG.info("Product artefact [{}] found.", productWar.getName());
                    // 
                    // extract war file
                    LOG.info("Product artefact [{}] will be extracted ...", productWar.getName());
                    ZipUtils.extract(productWar, extractedProductFolder.getPath());
                    LOG.info("Product [{}] extracted into target folder [{}].", productWar, targetFolder);
                    // 
                    productVersion = getVersion(extractedProductFolder);
                    break;
                }
            }
        }
        Assert.isTrue(StringUtils.isNotEmpty(productVersion), String.format("Product artefact not found in product folder [%s].", productFolder.getPath()));
        // 
        LOG.info("Product version [{}] resolved.", productVersion);
        // 
        // add modules into BE libs
        // extract FE sources - prepare for build
        // has to be lower - modules are linked automatically from parent folder
        File extractedFrontendFolder = new File(new File(targetFolder, "frontend"), "fe-sources");
        File productFrontendFolder = new File(String.format("%s/fe-sources", extractedProductFolder.getPath()));
        FileUtils.copyDirectory(productFrontendFolder, extractedFrontendFolder);
        // 
        File productFrontendModulesFolder = new File(String.format("%s/czechidm-modules", productFrontendFolder.getPath()));
        File extractedFrontendModulesFolder = new File(String.format("%s/czechidm-modules", extractedFrontendFolder.getPath()));
        List<String> installedModules = new ArrayList<>();
        List<File> installedJarModules = new ArrayList<>();
        Map<String, String> distinctModuleNames = Maps.newHashMap();
        // 
        if (!modulesFolder.exists()) {
            LOG.info("Folder with modules not found, modules will not be installed.");
        } else {
            ObjectMapper mapper = new ObjectMapper();
            // ensure files are sorted alphabetically
            File[] files = modulesFolder.listFiles();
            Arrays.sort(files);
            // 
            for (File module : files) {
                String moduleName = module.getName();
                // 
                FileUtils.copyFile(module, new File(String.format("%s/WEB-INF/lib", extractedProductFolder.getPath()), moduleName));
                // 
                // extract module jar into target
                File extractedModuleFolder = new File(targetFolder, FilenameUtils.removeExtension(moduleName));
                try {
                    ZipUtils.extract(module, extractedModuleFolder.getPath());
                    // 
                    // module name without version suffix
                    String simpleModuleName = null;
                    String backendModuleVersion = getVersion(extractedModuleFolder);
                    if (StringUtils.isNotEmpty(backendModuleVersion)) {
                        simpleModuleName = moduleName.replace(String.format("-%s", backendModuleVersion), "");
                        if (distinctModuleNames.containsKey(simpleModuleName)) {
                            throw new BuildException(String.format("Module [%s] cannot be installed twice. Remove one version from modules folder. Found versions [%s, %s].", simpleModuleName, distinctModuleNames.get(simpleModuleName), backendModuleVersion));
                        } else {
                            distinctModuleNames.put(simpleModuleName, backendModuleVersion);
                        }
                        // 
                        LOG.info("Backend module [{}] instaled in version [{}].", moduleName, // third party libraries without version in manifest ...
                        backendModuleVersion == null ? "n/a" : backendModuleVersion);
                    } else {
                        // third party libraries without version in manifest ...
                        LOG.info("Backend module [{}] instaled.", moduleName);
                    }
                    // 
                    // copy FE sources info product frontend
                    File moduleFrontendFolder = new File(String.format("%s/fe-sources/czechidm-modules", extractedModuleFolder.getPath()));
                    // 
                    if (moduleFrontendFolder.exists()) {
                        if (skipFrontendBuild) {
                            LOG.info("Frontend build is skipped. Module [{}] frontend will not be included.", moduleName);
                        } else {
                            // check BE vs. FE version -> throw exception otherwise
                            for (File moduleFolder : moduleFrontendFolder.listFiles()) {
                                File modulePackage = new File(moduleFolder.getPath(), "package.json");
                                try (InputStream is = new FileInputStream(modulePackage)) {
                                    // FIXME: refactor super class from product / project manager (DRY - #getCurrentFrontendModuleVersion).
                                    JsonNode json = mapper.readTree(IOUtils.toString(is, AttachableEntity.DEFAULT_CHARSET));
                                    String frontendModuleVersion = json.get("version").textValue();
                                    if (!StringUtils.equalsIgnoreCase(backendModuleVersion, frontendModuleVersion)) {
                                        throw new BuildException(String.format("Module [%s] versions differs [BE: %s] vs [FE: %s]. " + "Module is wrongly released or built. Build module properly and install him again.", moduleName, backendModuleVersion, frontendModuleVersion));
                                    }
                                    // 
                                    LOG.info("Frontend module [{}] instaled in version [{}].", moduleName, frontendModuleVersion);
                                }
                            }
                            // 
                            FileUtils.copyDirectory(moduleFrontendFolder, extractedFrontendModulesFolder);
                            // we need to know, what was installed in target war
                            FileUtils.copyDirectory(moduleFrontendFolder, productFrontendModulesFolder);
                        }
                    } else {
                        LOG.info("Module [{}] not contain frontend.", moduleName);
                    }
                    installedJarModules.add(module);
                } catch (ZipException ex) {
                    LOG.warn("Module [{}] cannot be extracted, is not .jar library. Library will be installed without frontend resolving.", module.getName());
                }
                // 
                installedModules.add(moduleName);
            }
        }
        // build FE - create new maven task and build
        if (!skipFrontendBuild) {
            // copy / override project frontends
            if (frontendFolder.exists() && frontendFolder.listFiles().length > 0) {
                FileUtils.copyDirectory(frontendFolder, extractedFrontendFolder);
                // we need to know, what was installed in target war
                FileUtils.copyDirectory(frontendFolder, productFrontendFolder);
                // 
                LOG.info("Custom or overriden frontend artifacts installed {}.", Arrays.stream(frontendFolder.listFiles()).map(f -> f.getName()).collect(Collectors.toList()));
            }
            // 
            LOG.info("Compile frontend application, this can take several minutes ...");
            prepareFrontendMavenProject(extractedFrontendFolder, targetFolder);
            mavenManager.command(targetFolder, "clean", "package", String.format("-Dnode.home=%s", nodeHome));
            LOG.info("Frontend successfully compiled.");
        } else {
            LOG.info("Frontend build is skipped. Product provided frontend will be used.");
        }
        // 
        // create new idm.war
        LOG.info("Build backend application with frontend included ...");
        prepareBackendMavenProject(extractedProductFolder, productVersion, installedJarModules, targetFolder);
        mavenManager.command(targetFolder, "clean", "package", String.format("-Dtool.version=%s", this.getClass().getPackage().getImplementationVersion()), String.format("-Dczechidm.version=%s", productVersion), String.format("-Dinstalled.modules=%s", installedModules));
        LOG.info("Application successfully built.");
        // 
        // move war to dist folder
        File projectWar = new File(distFolder, "idm.war");
        FileUtils.moveFile(new File(String.format("%s/target", targetFolder.getPath()), "idm.war"), projectWar);
        // 
        LOG.info("Deployable project artefact [idm.war] is available in dist directory,");
        LOG.info("with installed modules {}.", installedModules);
        // 
        return true;
    } catch (Exception ex) {
        throw new BuildException(ex.getLocalizedMessage(), ex);
    }
}
Also used : FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) ArrayList(java.util.ArrayList) JsonNode(com.fasterxml.jackson.databind.JsonNode) ZipException(java.util.zip.ZipException) FileInputStream(java.io.FileInputStream) ZipException(java.util.zip.ZipException) IOException(java.io.IOException) BuildException(eu.bcvsolutions.idm.tool.exception.BuildException) BuildException(eu.bcvsolutions.idm.tool.exception.BuildException) File(java.io.File) ObjectMapper(com.fasterxml.jackson.databind.ObjectMapper)

Example 4 with BuildException

use of eu.bcvsolutions.idm.tool.exception.BuildException in project CzechIdMng by bcvsolutions.

the class MavenManager method execute.

/**
 * Execute process.
 *
 * @param processBuilder
 * @param exceptionMessage
 * @throws InterruptedException
 * @throws FileNotFoundException
 * @throws IOException
 * @throws BuildException execute maven command failed
 * @return log file with process execution output
 */
protected void execute(ProcessBuilder processBuilder, String exceptionMessage) {
    try {
        // 
        Process process = processBuilder.start();
        // get logs
        BufferedReader processInput = new BufferedReader(new InputStreamReader(process.getInputStream()));
        BufferedReader processError = new BufferedReader(new InputStreamReader(process.getErrorStream()));
        String ligne;
        while ((ligne = processInput.readLine()) != null) {
            LOG.info(ligne);
        }
        while ((ligne = processError.readLine()) != null) {
            LOG.error(ligne);
        }
        // wait for end
        process.waitFor();
        // throw exception on failure
        if (process.exitValue() != 0) {
            LOG.error("Execute maven command failed [exit code: {}].", process.exitValue());
            // 
            throw new BuildException(String.format("Execute maven command failed [exit code: %s].", process.exitValue()));
        }
    } catch (InterruptedException | IOException ex) {
        throw new BuildException(ex);
    }
}
Also used : InputStreamReader(java.io.InputStreamReader) BufferedReader(java.io.BufferedReader) BuildException(eu.bcvsolutions.idm.tool.exception.BuildException) IOException(java.io.IOException)

Aggregations

BuildException (eu.bcvsolutions.idm.tool.exception.BuildException)4 IOException (java.io.IOException)4 File (java.io.File)3 FileInputStream (java.io.FileInputStream)3 InputStream (java.io.InputStream)3 JsonNode (com.fasterxml.jackson.databind.JsonNode)2 ObjectMapper (com.fasterxml.jackson.databind.ObjectMapper)2 ReleaseManager (eu.bcvsolutions.idm.tool.service.api.ReleaseManager)2 ArrayList (java.util.ArrayList)2 Arrays (java.util.Arrays)2 List (java.util.List)2 Collectors (java.util.stream.Collectors)2 ZipException (java.util.zip.ZipException)2 StringUtils (org.apache.commons.lang3.StringUtils)2 JsonEncoding (com.fasterxml.jackson.core.JsonEncoding)1 JsonGenerator (com.fasterxml.jackson.core.JsonGenerator)1 DeserializationFeature (com.fasterxml.jackson.databind.DeserializationFeature)1 SerializationFeature (com.fasterxml.jackson.databind.SerializationFeature)1 ArrayNode (com.fasterxml.jackson.databind.node.ArrayNode)1 ObjectNode (com.fasterxml.jackson.databind.node.ObjectNode)1