Skip to content

Commit

Permalink
Merge pull request #1 from amuniz/JENKINS-27039
Browse files Browse the repository at this point in the history
[JENKINS-27039] New step: milestone
  • Loading branch information
amuniz committed Sep 20, 2016
2 parents 24aa55c + 7a256f4 commit 802b461
Show file tree
Hide file tree
Showing 12 changed files with 1,026 additions and 0 deletions.
5 changes: 5 additions & 0 deletions .gitignore
@@ -0,0 +1,5 @@
target
.project
.classpath
.settings
work
82 changes: 82 additions & 0 deletions pom.xml
@@ -0,0 +1,82 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>plugin</artifactId>
<version>2.5</version>
<relativePath />
</parent>
<groupId>org.jenkins-ci.plugins</groupId>
<artifactId>pipeline-milestone-step</artifactId>
<version>1.0-SNAPSHOT</version>
<packaging>hpi</packaging>
<name>Pipeline: Milestone Step</name>
<url>https://wiki.jenkins-ci.org/display/JENKINS/Pipeline+Milestone+Step+Plugin</url>
<description>Plugin that provides the milestone step</description>

<licenses>
<license>
<name>MIT License</name>
<url>http://opensource.org/licenses/MIT</url>
</license>
</licenses>
<scm>
<connection>scm:git:git://github.com/jenkinsci/${project.artifactId}-plugin.git</connection>
<developerConnection>scm:git:git@github.com:jenkinsci/${project.artifactId}-plugin.git</developerConnection>
<url>https://github.com/jenkinsci/${project.artifactId}-plugin</url>
<tag>HEAD</tag>
</scm>
<repositories>
<repository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
</repository>
</repositories>
<pluginRepositories>
<pluginRepository>
<id>repo.jenkins-ci.org</id>
<url>http://repo.jenkins-ci.org/public/</url>
</pluginRepository>
</pluginRepositories>
<properties>
<jenkins.version>1.642.3</jenkins.version>
</properties>
<dependencies>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-step-api</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-api</artifactId>
<version>1.15</version>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-job</artifactId>
<version>2.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-cps</artifactId>
<version>1.15</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-basic-steps</artifactId>
<version>1.15</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.jenkins-ci.plugins.workflow</groupId>
<artifactId>workflow-support</artifactId>
<version>1.15</version>
<classifier>tests</classifier>
<scope>test</scope>
</dependency>
</dependencies>
</project>
@@ -0,0 +1,60 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.pipeline.milestone;

import hudson.model.Run;
import jenkins.model.CauseOfInterruption;

/**
* Records that a build was canceled because it reached a milestone but a newer build already passed it, or
* a newer build {@link Milestone#wentAway(Run)} from the last milestone the build passed.
*/
public final class CancelledCause extends CauseOfInterruption {

private static final long serialVersionUID = 1;

private final String newerBuild;

private final String displayName;

CancelledCause(Run<?,?> newerBuild) {
this.newerBuild = newerBuild.getExternalizableId();
this.displayName = newerBuild.getDisplayName();
}

CancelledCause(String newerBuild) {
this.newerBuild = newerBuild;
// No display name available, use what we have at this point
this.displayName = newerBuild;
}

public Run<?,?> getNewerBuild() {
return Run.fromExternalizableId(newerBuild);
}

@Override public String getShortDescription() {
return "Superseded by " + displayName;
}

}
@@ -0,0 +1,80 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.pipeline.milestone;

import java.util.Set;
import java.util.TreeSet;

import javax.annotation.CheckForNull;

import org.jenkinsci.plugins.workflow.steps.StepContext;

import hudson.model.Run;

class Milestone {

/**
* Milestone ordinal.
*/
final Integer ordinal;

/**
* Numbers of builds that passed this milestone but haven't passed the next one.
*/
final Set<Integer> inSight = new TreeSet<Integer>();

/**
* Last build that passed through the milestone, or null if none passed yet.
*/
@CheckForNull
Integer lastBuild;

Milestone(Integer ordinal) {
this.ordinal = ordinal;
}

@Override public String toString() {
return "Milestone[inSight=" + inSight + "]";
}

public void pass(StepContext context, Run<?, ?> build) {
lastBuild = build.getNumber();
inSight.add(build.getNumber());
}

/**
* Called when a build passes the next milestone.
*
* @param build the build passing the next milestone.
* @return true if the build was in sight (exists in inSight), false otherwise.
*/
public boolean wentAway(Run<?, ?> build) {
if (inSight.contains(build.getNumber())) {
inSight.remove(build.getNumber()); // XSTR-757
return true;
} else {
return false;
}
}
}
@@ -0,0 +1,39 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.pipeline.milestone;

import org.jenkinsci.plugins.workflow.actions.LabelAction;
import org.jenkinsci.plugins.workflow.actions.StageAction;

class MilestoneAction extends LabelAction implements StageAction {

MilestoneAction(String label) {
super(label);
}

@Override
public String getStageName() {
return getDisplayName();
}
}
@@ -0,0 +1,127 @@
/*
* The MIT License
*
* Copyright (c) 2016, CloudBees, Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
package org.jenkinsci.plugins.pipeline.milestone;


import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jenkinsci.plugins.workflow.steps.AbstractStepDescriptorImpl;
import org.jenkinsci.plugins.workflow.steps.AbstractStepImpl;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;

import edu.umd.cs.findbugs.annotations.CheckForNull;
import hudson.Extension;

/**
* This step can be used to grant:
* <ol>
* <li>Builds pass through the step in order (taking the build number as sorter field)</li>
* <li>Older builds will not proceed (they are aborted) if a newer one already entered the milestone</li>
* <li>When a build passes a milestone, any older build that passed the previous milestone - but not this one - is aborted.</li>
* <li>Once a build passes the milestone, it will be never aborted by a newer build that didn't pass the milestone yet.</li>
* </ol>
*/
public class MilestoneStep extends AbstractStepImpl {

/**
* Optional milestone label.
*/
private String label;

/**
* Optional ordinal.
*/
private Integer ordinal;

@DataBoundConstructor
public MilestoneStep(Integer ordinal) {
this.ordinal = ordinal;
}

@DataBoundSetter
public void setLabel(String label) {
this.label = label;
}

@CheckForNull
public String getLabel() {
return label;
}

@CheckForNull
public Integer getOrdinal() {
return ordinal;
}

@Extension
public static final class DescriptorImpl extends AbstractStepDescriptorImpl {

private Map<String, Map<Integer, Milestone>> milestonesByOrdinalByJob;

private static final Logger LOGGER = Logger.getLogger(MilestoneStep.class.getName());

public DescriptorImpl() {
super(MilestoneStepExecution.class);
}

@Override
public String getFunctionName() {
return "milestone";
}

@Override
public String getDisplayName() {
return "The milestone step forces all builds to go through in order";
}

@Override
public void load() {
super.load();
if (milestonesByOrdinalByJob == null) {
milestonesByOrdinalByJob = new TreeMap<String, Map<Integer, Milestone>>();
}
LOGGER.log(Level.FINE, "load: {0}", milestonesByOrdinalByJob);
}

@Override
public void save() {
super.save();
LOGGER.log(Level.FINE, "save: {0}", milestonesByOrdinalByJob);
}

public Map<String, Map<Integer, Milestone>> getMilestonesByOrdinalByJob() {
return milestonesByOrdinalByJob;
}

/* package */ void setMilestonesByOrdinalByJob(Map<String, Map<Integer, Milestone>> m) {
milestonesByOrdinalByJob = m;
}

}

}

0 comments on commit 802b461

Please sign in to comment.