Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement DontKeepBuildForeverAction #80

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package hudson.plugins.promoted_builds;

import hudson.Extension;
import hudson.Launcher;
import hudson.model.AbstractBuild;
import hudson.model.AbstractProject;
import hudson.model.BuildListener;
import hudson.model.Result;
import hudson.tasks.BuildStepDescriptor;
import hudson.tasks.BuildStepMonitor;
import hudson.tasks.Notifier;
import hudson.tasks.Publisher;
import org.kohsuke.stapler.DataBoundConstructor;

import java.io.IOException;
import java.io.PrintStream;

public class DontKeepBuildForeverAction extends Notifier {

@DataBoundConstructor
public DontKeepBuildForeverAction() { }

private static final Result PROMOTION_RESULT_MUST_BE_AT_LEAST = Result.UNSTABLE;

public BuildStepMonitor getRequiredMonitorService() {
return BuildStepMonitor.BUILD;
}

@Override
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener) throws InterruptedException, IOException {
PrintStream console = listener.getLogger();
// only applicable to promotions, so should be impossible not to be one, but check anyway
if (!(build instanceof Promotion)) {
console.println(Messages.KeepBuildForEverAction_console_notPromotion());
build.setResult(Result.FAILURE);
return false;
}

final Result buildResult = build.getResult();
if (buildResult != null && buildResult.isWorseThan(PROMOTION_RESULT_MUST_BE_AT_LEAST)) {
console.println(Messages.KeepBuildForEverAction_console_promotionNotGoodEnough(build.getResult()));
return true;
}
AbstractBuild promoted = ((Promotion) build).getTarget();
console.println(Messages.KeepBuildForEverAction_console_notKeepingBuild());
promoted.keepLog(false);
return true;
}

@Extension
public static class KeepBuildForeverDescriptor extends BuildStepDescriptor<Publisher> {

@Override
public boolean isApplicable(Class<? extends AbstractProject> jobType) {
return jobType == PromotionProcess.class;
}

@Override
public String getDisplayName() {
return Messages.DontKeepBuildForEverAction_descriptor_displayName();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,8 @@ KeepBuildForEverAction.descriptor.displayName=Keep Build Forever
KeepBuildForEverAction.console.notPromotion=This build is not a promotion, how did we get here? Not keeping build.
KeepBuildForEverAction.console.promotionNotGoodEnough=Promotion build result [{0}] is not good enough. Not keeping build.
KeepBuildForEverAction.console.keepingBuild=Marking build to keep forever.
KeepBuildForEverAction.console.notKeepingBuild=Unmarking build to keep forever - this build may be discarded in the future.
DontKeepBuildForEverAction.descriptor.displayName=Don't Keep Build Forever
Promotion.Permissions.Title=Promotion
Promotion.PromotePermission.Description=This permission allows user to use force promotion and re-execution of promotion

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
package hudson.plugins.promoted_builds;

import hudson.Launcher;
import hudson.model.*;
import hudson.plugins.promoted_builds.JobPropertyImpl;
import hudson.plugins.promoted_builds.DontKeepBuildForeverAction;
import hudson.plugins.promoted_builds.KeepBuildForeverAction;
import hudson.plugins.promoted_builds.PromotionProcess;
import hudson.plugins.promoted_builds.conditions.DownstreamPassCondition;
import hudson.tasks.ArtifactArchiver;
import hudson.tasks.Fingerprinter;
import hudson.tasks.Recorder;
import org.jvnet.hudson.test.HudsonTestCase;
import org.jvnet.hudson.test.TestBuilder;

import java.io.IOException;
import java.util.Arrays;
import java.util.List;

public class DontKeepBuildForeverActionTest extends HudsonTestCase {

public void testCanMarkBuildKeepForever() throws Exception {
FreeStyleProject upJob = createProject("up");
upJob.getBuildersList().add(successfulBuilder());
FreeStyleProject downJob = createProject("down");
downJob.getBuildersList().add(successfulBuilder());

PromotionProcess promotionJob = createDownstreamSuccessPromotion(upJob, downJob);
promotionJob.getBuildSteps().add(new KeepBuildForeverAction());
promotionJob.getBuildSteps().add(new DontKeepBuildForeverAction());

FreeStyleBuild upBuild = assertBuildStatusSuccess(upJob.scheduleBuild2(0).get());
assertFalse(upBuild.isKeepLog());

assertBuildStatusSuccess(downJob.scheduleBuild2(0).get());
waitForBuild(promotionJob, 1);
assertFalse(upBuild.isKeepLog());
}

public void testDoesNotMarkBuildIfPromotionNotGoodEnough() throws Exception {
FreeStyleProject upJob = createProject("up");
upJob.getBuildersList().add(successfulBuilder());
FreeStyleProject downJob = createProject("down");
downJob.getBuildersList().add(successfulBuilder());

PromotionProcess promotionJob = createDownstreamSuccessPromotion(upJob, downJob);
promotionJob.getBuildSteps().add(new FixedResultBuilder(Result.FAILURE));
promotionJob.getBuildSteps().add(new KeepBuildForeverAction());
promotionJob.getBuildSteps().add(new DontKeepBuildForeverAction());

FreeStyleBuild upBuild = assertBuildStatusSuccess(upJob.scheduleBuild2(0).get());
assertFalse(upBuild.isKeepLog());

assertBuildStatusSuccess(downJob.scheduleBuild2(0).get());
waitForBuild(promotionJob, 1);
assertFalse(upBuild.isKeepLog());
}

public void testDoesNotCareAboutResultOfOriginalBuild() throws Exception {
FreeStyleProject upJob = createProject("up");
upJob.getBuildersList().add(new FixedResultBuilder(Result.FAILURE));
FreeStyleProject downJob = createProject("down");
downJob.getBuildersList().add(successfulBuilder());

PromotionProcess promotionJob = createDownstreamSuccessPromotion(upJob, downJob);
promotionJob.getBuildSteps().add(new KeepBuildForeverAction());
promotionJob.getBuildSteps().add(new DontKeepBuildForeverAction());

FreeStyleBuild upBuild = assertBuildStatus(Result.FAILURE, upJob.scheduleBuild2(0).get());
assertFalse(upBuild.isKeepLog());

assertBuildStatusSuccess(downJob.scheduleBuild2(0).get());
waitForBuild(promotionJob, 1);
assertFalse(upBuild.isKeepLog());
}

public void testDoesNotMarkBuildIfBuildNotPromotion() throws Exception {
FreeStyleProject job = createProject("job");
job.getBuildersList().add(successfulBuilder());
job.getPublishersList().add(new KeepBuildForeverAction());
job.getPublishersList().add(new DontKeepBuildForeverAction());

FreeStyleBuild build = assertBuildStatus(Result.FAILURE, job.scheduleBuild2(0).get());
assertFalse(build.isKeepLog());
}

private void waitForBuild(final Job job, final int buildNumber) throws Exception {
waitFor(new WaitCondition() {
public boolean isMet() {
return (job.getBuildByNumber(buildNumber) != null) && !job.getBuildByNumber(buildNumber).isBuilding();
}
}, 2000);
}

private void waitFor(final WaitCondition condition, long timeout) throws Exception {
Thread waiter = new Thread() {
public void run() {
try {
while (!condition.isMet()) {
Thread.sleep(100);
}
} catch (InterruptedException ie) { }
}
};
waiter.start();
waiter.join(timeout);
if (waiter.isAlive()) {
waiter.interrupt();
}
if (!condition.isMet())
fail("Condition not met");
}

private PromotionProcess createDownstreamSuccessPromotion(FreeStyleProject upStream, FreeStyleProject downStream)
throws Descriptor.FormException, IOException {
JobPropertyImpl promotionProperty = new JobPropertyImpl(upStream);
upStream.addProperty(promotionProperty);
PromotionProcess promotionJob = promotionProperty.addProcess("promotion");
promotionJob.conditions.add(new DownstreamPassCondition(downStream.getName()));
return promotionJob;
}

private FreeStyleProject createProject(String name) throws Exception {
FreeStyleProject project = createFreeStyleProject(name);
project.getPublishersList().replaceBy(createFingerprinters());
return project;
}

private List<Recorder> createFingerprinters() {
return Arrays.asList(
new ArtifactArchiver("*", null, false),
new Fingerprinter("", true)
);
}

private FixedResultBuilder successfulBuilder() {
return new FixedResultBuilder(Result.SUCCESS);
}

public interface WaitCondition {
boolean isMet();
}

public static class FixedResultBuilder extends TestBuilder {
private Result buildResult;
FixedResultBuilder(Result buildResult) {
this.buildResult = buildResult;
}
public boolean perform(AbstractBuild<?, ?> build, Launcher launcher, BuildListener listener)
throws InterruptedException, IOException {
build.getWorkspace().child("my.file").write("Hello world!", "UTF-8");
build.setResult(buildResult);
return true;
}
}

}