package org.jfrog.hudson.pipeline.steps; import com.google.inject.Inject; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.remoting.Callable; import org.apache.commons.collections.map.HashedMap; import org.apache.commons.lang.StringUtils; import org.apache.maven.model.Model; import org.apache.maven.model.io.xpp3.MavenXpp3Reader; import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl; import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl; import org.jenkinsci.plugins.workflow.steps.AbstractSynchronousStepExecution; import org.jenkinsci.plugins.workflow.steps.StepContextParameter; import org.jfrog.build.extractor.maven.reader.ModuleName; import org.jfrog.build.extractor.maven.transformer.PomTransformer; import org.kohsuke.stapler.DataBoundConstructor; import java.io.BufferedReader; import java.io.File; import java.io.FileReader; import java.io.IOException; import java.util.List; import java.util.Map; /** * Created by tamirh on 20/11/2016. */ public class MavenDescriptorStep extends AbstractStepImpl { private String pomFile = "pom.xml"; private String version = ""; private Map<String, String> versionPerModule = new HashedMap(); private boolean failOnSnapshot; private boolean dryRun; @DataBoundConstructor public MavenDescriptorStep(String pomFile, String version, Map<String, String> versionPerModule, boolean failOnSnapshot, boolean dryRun) { this.pomFile = pomFile; this.version = version; this.versionPerModule = versionPerModule; this.failOnSnapshot = failOnSnapshot; this.dryRun = dryRun; } public String getPomFile() { return pomFile; } public String getVersion() { return version; } public boolean isFailOnSnapshot() { return failOnSnapshot; } public boolean isDryRun() { return dryRun; } public Map<String, String> getVersionPerModule() { return versionPerModule; } public static class Execution extends AbstractSynchronousStepExecution<Boolean> { private static final long serialVersionUID = 1L; @Inject(optional = true) private transient MavenDescriptorStep step; @StepContextParameter private transient FilePath ws; @StepContextParameter private transient Launcher launcher; private String pomFile; private boolean failOnSnapshot; private boolean dryRun; private String version = ""; private Map<String, String> versionPerModule = new HashedMap(); @Override protected Boolean run() throws Exception { pomFile = new FilePath(ws, step.getPomFile()).getRemote(); failOnSnapshot = step.isFailOnSnapshot(); dryRun = step.isDryRun(); this.version = step.getVersion(); this.versionPerModule = step.getVersionPerModule(); Boolean call = launcher.getChannel().call(new Callable<Boolean, IOException>() { public Boolean call() throws IOException { return transformPoms(); } }); return call; } public boolean transformPoms() { String filePath = ""; String fileName = pomFile; int index = StringUtils.lastIndexOf(pomFile, File.separator); if (index > 0) { filePath = StringUtils.substring(pomFile, 0, index + 1); fileName = StringUtils.substring(pomFile, index + 1); } final Map<ModuleName, String> modules = new HashedMap(); Map<ModuleName, String> modulesVersion = new HashedMap(); findPomModules(filePath, fileName, modules); return execTransformtion(modules, modulesVersion); } private boolean execTransformtion(Map<ModuleName, String> modules, Map<ModuleName, String> modulesVersion) { boolean isTransformed = false; for (Map.Entry<ModuleName, String> module : modules.entrySet()) { modulesVersion.put(module.getKey(), getModuleVersion(module.getKey())); } for (Map.Entry<ModuleName, String> module : modules.entrySet()) { PomTransformer pomTransformer = new PomTransformer(module.getKey(), modulesVersion, null, failOnSnapshot, dryRun); try { isTransformed |= pomTransformer.transform(new File(module.getValue())); } catch (IOException e) { throw new RuntimeException(e); } } return isTransformed; } private void findPomModules(String filePath, String fileName, Map<ModuleName, String> result) { Model model; String pomPath = filePath + fileName; BufferedReader in = null; try { in = new BufferedReader(new FileReader(pomPath)); MavenXpp3Reader reader = new MavenXpp3Reader(); model = reader.read(in); } catch (Exception e) { throw new RuntimeException(e); } finally { if (in != null) { try { in.close(); } catch (Exception e) { // Ignored } } } String parentGroupId = null; String parentArtifactId = null; if (model.getParent() != null) { parentArtifactId = model.getParent().getArtifactId(); parentGroupId = model.getParent().getGroupId(); } String groupId = model.getGroupId() != null ? model.getGroupId() : parentGroupId; String artifactId = model.getArtifactId() != null ? model.getArtifactId() : parentArtifactId; if (groupId == null || artifactId == null) { throw new IllegalStateException("artifactId and/or groupId could not be found in POM file: " + pomPath); } result.put(new ModuleName(groupId, artifactId), pomPath); List<String> modules = model.getModules(); for (String module : modules) { String tempFilePath = StringUtils.endsWith(filePath, File.separator) ? filePath + module + File.separator : filePath + File.separator + module + File.separator; findPomModules(tempFilePath, "pom.xml", result); } } private String getModuleVersion(ModuleName module) { String moduleIdentifier = module.getGroupId() + ":" + module.getArtifactId(); String version = versionPerModule.get(moduleIdentifier); if (StringUtils.isNotEmpty(version)) { return version; } if (StringUtils.isEmpty(this.version)) { throw new RuntimeException("Can't find version for module" + moduleIdentifier + "."); } return this.version; } } @Extension public static final class DescriptorImpl extends AbstractStepDescriptorImpl { public DescriptorImpl() { super(MavenDescriptorStep.Execution.class); } @Override public String getFunctionName() { return "MavenDescriptorStep"; } @Override public String getDisplayName() { return "Get Artifactory Maven descriptor"; } @Override public boolean isAdvanced() { return true; } } }