Java tutorial
/* * Copyright 2014 by Yields. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package io.yields.plugins.kpi; import net.sf.json.JSONObject; import org.apache.commons.io.FileUtils; import org.apache.commons.lang.StringUtils; import org.kohsuke.stapler.DataBoundConstructor; import org.kohsuke.stapler.QueryParameter; import org.kohsuke.stapler.StaplerRequest; import java.io.File; import java.io.IOException; import java.io.PrintStream; import java.util.Arrays; import java.util.Collections; import java.util.Comparator; import java.util.List; import javax.servlet.ServletException; import hudson.Extension; import hudson.FilePath; import hudson.Launcher; import hudson.model.AbstractBuild; import hudson.model.AbstractProject; import hudson.model.Action; import hudson.model.BuildListener; import hudson.model.Result; import hudson.tasks.BuildStepDescriptor; import hudson.tasks.BuildStepMonitor; import hudson.tasks.Publisher; import hudson.tasks.Recorder; import hudson.util.FormValidation; import static io.yields.plugins.kpi.LocalMessages.PUBLISHER_DISPLAY_NAME; import static java.lang.Long.valueOf; import static java.lang.String.format; import static org.apache.commons.lang.StringUtils.isNotBlank; /** * Entry point for the KPI Plugin. */ public class KPIReportPublisher extends Recorder { public static final String FOLDER_NAME = "yields"; public static final String FOLDER_NAME_DATA_SET = "yields_data"; public static final class DescriptorImpl extends BuildStepDescriptor<Publisher> { @Override public String getDisplayName() { return PUBLISHER_DISPLAY_NAME.toString(); } @Override public String getHelpFile() { return "/plugin/yields-dashboard/help.html"; } private String path; private Integer trendSize; private Integer detailSize; public DescriptorImpl() { load(); } public FormValidation doCheckPath(@QueryParameter String value) throws IOException, ServletException { if (StringUtils.isNotBlank(value)) { if (!new File(value).exists()) { return FormValidation .error("Please provide a valid folder, '%s' does not exist or is not a folder", value); } } return FormValidation.ok(); } public FormValidation doCheckTrendSize(@QueryParameter Integer value) throws IOException, ServletException { if (value != null && value < 0) { return FormValidation.error("Please provide a positive size"); } return FormValidation.ok(); } public FormValidation doCheckDetailSize(@QueryParameter Integer value) throws IOException, ServletException { if (value != null && value < 0) { return FormValidation.error("Please provide a positive size"); } return FormValidation.ok(); } public boolean isApplicable(Class<? extends AbstractProject> aClass) { return true; } @Override public boolean configure(StaplerRequest req, JSONObject formData) throws FormException { path = formData.getString("path"); trendSize = formData.getInt("trendSize"); detailSize = formData.getInt("detailSize"); save(); return super.configure(req, formData); } public String getPath() { return path; } public Integer getTrendSize() { return trendSize; } public Integer getDetailSize() { return detailSize; } } @Extension public static final DescriptorImpl DESCRIPTOR = new DescriptorImpl(); private final KPIReportConfig config; private final DataSetExportConfig dataSetExportConfig; private String path; private Integer trendSize; private Integer detailSize; private String exportPath; @DataBoundConstructor public KPIReportPublisher(String path, Integer trendSize, Integer detailSize, String exportPath) { setPath(path); setTrendSize(trendSize); setDetailSize(detailSize); setExportPath(exportPath); if (trendSize == null) { trendSize = 10; } if (detailSize == null) { detailSize = 3; } if (isNotBlank(path)) { this.config = new KPIReportConfig(new File(path, FOLDER_NAME), trendSize, detailSize); } else { this.config = new KPIReportConfig(new File(FileUtils.getTempDirectory(), FOLDER_NAME), trendSize, detailSize); } if (isNotBlank(exportPath)) { this.dataSetExportConfig = new DataSetExportConfig(new File(exportPath)); } else { this.dataSetExportConfig = null; } // TODO changed config, re-init builds with new config } public String getPath() { return path; } public void setPath(String path) { this.path = path; } public Integer getTrendSize() { return trendSize; } public void setTrendSize(Integer trendSize) { this.trendSize = trendSize; } public Integer getDetailSize() { return detailSize; } public void setDetailSize(Integer detailSize) { this.detailSize = detailSize; } public String getExportPath() { return exportPath; } public void setExportPath(String exportPath) { this.exportPath = exportPath; } @Override public DescriptorImpl getDescriptor() { return DESCRIPTOR; } @Override public Action getProjectAction(AbstractProject<?, ?> project) { return new KPIReportProjectAction(project, config); } public BuildStepMonitor getRequiredMonitorService() { return BuildStepMonitor.NONE; } private FilePath getWorkspace(AbstractBuild build) { FilePath workspace = build.getWorkspace(); if (workspace == null) { workspace = build.getProject().getSomeWorkspace(); } return workspace; } @Override public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException { PrintStream logger = listener.getLogger(); if (Result.SUCCESS == build.getResult()) { FilePath workspace = getWorkspace(build); // copy results from yields folder to build folder FilePath buildFolder = workspace.child(format("builds/%d/yields", build.getNumber())); buildFolder.mkdirs(); logger.printf("[YIELDS] Scanning for KPI Scores in path %s (trendSize = %d, detailSize = %d)\n", config.getPath().getAbsolutePath(), config.getTrendSize(), config.getDetailSize()); // copy the latest folder to the build folder File[] folders = config.getPath().listFiles(); if (folders != null) { List<File> buildFolders = Arrays.asList(folders); Collections.sort(buildFolders, new Comparator<File>() { @Override public int compare(File file, File other) { return valueOf(other.lastModified()).compareTo(valueOf(file.lastModified())); } }); new FilePath(buildFolders.get(0)).copyRecursiveTo(buildFolder); logger.printf("[YIELDS] Copied KPI Scores from %s into %s\n", buildFolders.get(0), buildFolder); } else { logger.printf("[YIELDS] No KPI Scores found in %s, nothing will be copied\n", config.getPath()); } } else { logger.printf("[YIELDS] No KPI Scores to copy, build has result %s\n", build.getResult()); } if (Result.SUCCESS == build.getResult()) { if (dataSetExportConfig != null) { // copy the latest folder to the configured export filter File sourceFolder = new File(FileUtils.getTempDirectory(), FOLDER_NAME_DATA_SET); // move exported data sets from yields_data folder to configured export filter logger.printf("[YIELDS_DATA] Scanning for KPI Data Sets in path %s\n", sourceFolder.getAbsolutePath()); File[] folders = sourceFolder.listFiles(); if (folders != null) { List<File> exportFolders = Arrays.asList(folders); Collections.sort(exportFolders, new Comparator<File>() { @Override public int compare(File file, File other) { return valueOf(other.lastModified()).compareTo(valueOf(file.lastModified())); } }); FileUtils.moveDirectoryToDirectory(exportFolders.get(0), dataSetExportConfig.getPath(), true); logger.printf("[YIELDS_DATA] Moved KPI Data Sets from %s into %s\n", exportFolders.get(0).getAbsolutePath(), dataSetExportConfig.getPath().getAbsolutePath()); } else { logger.printf("[YIELDS_DATA] No KPI Data Sets found in %s, nothing will be moved\n", sourceFolder.getAbsolutePath()); } } else { logger.printf("[YIELDS_DATA] No KPI export path configured\n"); } } else { logger.printf("[YIELDS_DATA] No KPI Data Sets to move, build has result %s\n", build.getResult()); } KPIReport report = new KPIReportService().getReport(build, config.getTrendSize(), listener.getLogger()); listener.getLogger().printf("[YIELDS] Retrieved KPI Report with %d previous KPI report(s)\n", config.getTrendSize() - 1); KPIReportBuildAction buildAction = new KPIReportBuildAction(build, report, config.getTrendSize()); build.addAction(buildAction); // TODO fail build if configured to fail and 1 or more scores went down compared to previous build (build.setResult) return true; } }