io.yields.plugins.kpi.KPIReportPublisher.java Source code

Java tutorial

Introduction

Here is the source code for io.yields.plugins.kpi.KPIReportPublisher.java

Source

/*
 * 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;
    }

}