diff --git a/.README/4_Supports_Claim_Plugin.png b/.README/4_Supports_Claim_Plugin.png new file mode 100644 index 000000000..1d3984cc3 Binary files /dev/null and b/.README/4_Supports_Claim_Plugin.png differ diff --git a/README.md b/README.md index 22bb4228d..d2796e598 100644 --- a/README.md +++ b/README.md @@ -32,6 +32,7 @@ All the features I'm hoping to add in the near future are listed in the "Roadmap    + ## TDD @@ -54,7 +55,7 @@ in the [near future](http://caniuse.com/flexbox). 1. Display what triggered the build (SCM change, another job, manual) 1. Display how long has a given job been failing for -1. Support for [Claim Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Claim+plugin) +1. ~~Support for [Claim Plugin](https://wiki.jenkins-ci.org/display/JENKINS/Claim+plugin)~~ 1. Support for [Gravatar](http://gravatar.com) 1. Display parameters of parametrized jobs 1. ~~Persist layout configuration changes in a long-lived cookie.~~ diff --git a/pom.xml b/pom.xml index f71655d4a..7ca4015dc 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ <groupId>org.jenkins-ci.plugins</groupId> <artifactId>build-monitor-plugin</artifactId> - <version>1.1-SNAPSHOT</version> + <version>1.2-SNAPSHOT</version> <packaging>hpi</packaging> <name>Build Monitor View</name> @@ -109,7 +109,16 @@ <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> + <scope>test</scope> </dependency> + + <dependency> + <groupId>org.jenkins-ci.plugins</groupId> + <artifactId>claim</artifactId> + <version>2.1</version> + <optional>true</optional> + </dependency> + </dependencies> <build> diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView.java index 1cc8c578a..66055bb3c 100644 --- a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView.java +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView.java @@ -24,11 +24,10 @@ package com.smartcodeltd.jenkinsci.plugins.buildmonitor; import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.JobView; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.BuildAugmentor; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.Claim; import hudson.Extension; -import hudson.model.AbstractProject; -import hudson.model.ListView; -import hudson.model.TopLevelItem; -import hudson.model.ViewDescriptor; +import hudson.model.*; import hudson.util.FormValidation; import net.sf.json.JSONObject; import net.sf.json.JSONSerializer; @@ -110,11 +109,21 @@ private List<JobView> jobViews() { if (item instanceof AbstractProject) { AbstractProject project = (AbstractProject) item; if (! project.isDisabled()) { - jobs.add(JobView.of(project)); + jobs.add(JobView.of(project, withAugmentationsIfTheyArePresent())); } } } return jobs; } + + private BuildAugmentor withAugmentationsIfTheyArePresent() { + BuildAugmentor augmentor = new BuildAugmentor(); + + if (Hudson.getInstance().getPlugin("claim") != null) { + augmentor.support(Claim.class); + } + + return augmentor; + } } \ No newline at end of file diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildView.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildView.java index 15f0587a3..cd6e48b7c 100644 --- a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildView.java +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildView.java @@ -1,5 +1,7 @@ package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.BuildAugmentor; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.Claim; import hudson.model.AbstractBuild; import hudson.model.Result; import hudson.model.Run; @@ -13,13 +15,14 @@ public class BuildView implements BuildViewModel { private final Run<?,?> build; private final Date systemTime; + private final BuildAugmentor augmentor; public static BuildView of(Run<?, ?> build) { - return new BuildView(build, new Date()); + return new BuildView(build, new BuildAugmentor(), new Date()); } - public static BuildView of(Run<?, ?> build, Date systemTime) { - return new BuildView(build, systemTime); + public static BuildView of(Run<?, ?> build, BuildAugmentor augmentor, Date systemTime) { + return new BuildView(build, augmentor, systemTime); } @@ -93,7 +96,7 @@ public boolean hasPreviousBuild() { @Override public BuildViewModel previousBuild() { - return new BuildView(build.getPreviousBuild(), systemTime); + return new BuildView(build.getPreviousBuild(), augmentor, systemTime); } @Override @@ -113,6 +116,25 @@ public Set<String> culprits() { return culprits; } + @Override + public boolean isClaimed() { + return claim().wasMade(); + } + + @Override + public String claimant() { + return claim().author(); + } + + @Override + public String reasonForClaim() { + return claim().reason(); + } + + private Claim claim() { + return augmentor.detailsOf(build, Claim.class); + } + public String toString() { return name(); } @@ -127,8 +149,9 @@ private long whenTheBuildStarted() { } - private BuildView(Run<?, ?> build, Date systemTime) { + private BuildView(Run<?, ?> build, BuildAugmentor augmentor, Date systemTime) { this.build = build; this.systemTime = systemTime; + this.augmentor = augmentor; } } diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildViewModel.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildViewModel.java index d1d41025f..fa1025092 100644 --- a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildViewModel.java +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/BuildViewModel.java @@ -19,4 +19,8 @@ public interface BuildViewModel { public BuildViewModel previousBuild(); public Set<String> culprits(); + + boolean isClaimed(); + String claimant(); + String reasonForClaim(); } diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobView.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobView.java index 0e1c0b8cd..b9182acb2 100644 --- a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobView.java +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobView.java @@ -1,5 +1,6 @@ package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.BuildAugmentor; import hudson.model.*; import org.codehaus.jackson.annotate.JsonProperty; @@ -13,13 +14,18 @@ public class JobView { private final Date systemTime; private final Job<?, ?> job; + private final BuildAugmentor augmentor; public static JobView of(Job<?, ?> job) { - return new JobView(job, new Date()); + return new JobView(job, new BuildAugmentor(), new Date()); + } + + public static JobView of(Job<?, ?> job, BuildAugmentor augmentor) { + return new JobView(job, augmentor, new Date()); } public static JobView of(Job<?, ?> job, Date systemTime) { - return new JobView(job, systemTime); + return new JobView(job, new BuildAugmentor(), systemTime); } @JsonProperty @@ -45,6 +51,10 @@ public String status() { status += " running"; } + if (lastCompletedBuild().isClaimed()) { + status += " claimed"; + } + return status; } @@ -102,13 +112,29 @@ public Set<String> culprits() { return culprits; } + @JsonProperty + public boolean isClaimed() { + return lastCompletedBuild().isClaimed(); + } + + @JsonProperty + public String claimAuthor() { + return lastCompletedBuild().claimant(); + } + + @JsonProperty + public String claimReason() { + return lastCompletedBuild().reasonForClaim(); + } + public String toString() { return name(); } - private JobView(Job<?, ?> job, Date systemTime) { - this.job = job; + private JobView(Job<?, ?> job, BuildAugmentor augmentor, Date systemTime) { + this.job = job; + this.augmentor = augmentor; this.systemTime = systemTime; } @@ -130,6 +156,6 @@ private BuildViewModel buildViewOf(Run<?, ?> build) { return new NullBuildView(); } - return BuildView.of(job.getLastBuild(), systemTime); + return BuildView.of(job.getLastBuild(), augmentor, systemTime); } } \ No newline at end of file diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/NullBuildView.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/NullBuildView.java index 8ab0d4be9..b9c04c7e8 100644 --- a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/NullBuildView.java +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/NullBuildView.java @@ -61,4 +61,19 @@ public BuildViewModel previousBuild() { public Set<String> culprits() { return new HashSet<String>(); } + + @Override + public boolean isClaimed() { + return false; + } + + @Override + public String claimant() { + return null; + } + + @Override + public String reasonForClaim() { + return null; + } } diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/Augmentation.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/Augmentation.java new file mode 100644 index 000000000..cb42aa922 --- /dev/null +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/Augmentation.java @@ -0,0 +1,4 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins; + +public interface Augmentation { +} diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/BuildAugmentor.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/BuildAugmentor.java new file mode 100644 index 000000000..9e35b02d3 --- /dev/null +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/BuildAugmentor.java @@ -0,0 +1,32 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins; + +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.Claim; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.Claimed; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.NotClaimed; +import hudson.model.Run; +import hudson.plugins.claim.ClaimBuildAction; + +import java.util.HashSet; +import java.util.Set; + +public class BuildAugmentor { + + private Set<Class<? extends Augmentation>> recognisedAugmentations = new HashSet<Class<? extends Augmentation>>(); + + public Claim detailsOf(Run<?, ?> build, Class<Claim> augmentation) { + // todo: remove the below naive implementation with something better once there is more plugins to support ... + if (recognisedAugmentations.contains(augmentation)) { + ClaimBuildAction action = build.getAction(ClaimBuildAction.class); + + if (action != null) { + return new Claimed(action); + } + } + + return new NotClaimed(); + } + + public void support(Class<? extends Augmentation> typeOfAugmentation) { + recognisedAugmentations.add(typeOfAugmentation); + } +} diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/Claim.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/Claim.java new file mode 100644 index 000000000..06d6982f0 --- /dev/null +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/Claim.java @@ -0,0 +1,9 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim; + +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.Augmentation; + +public interface Claim extends Augmentation { + public boolean wasMade(); + public String author(); + public String reason(); +} diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/Claimed.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/Claimed.java new file mode 100644 index 000000000..dd73fe169 --- /dev/null +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/Claimed.java @@ -0,0 +1,30 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim; + +import hudson.plugins.claim.ClaimBuildAction; + +public class Claimed implements Claim { + private final ClaimBuildAction action; + + public Claimed(ClaimBuildAction action) { + this.action = action; + } + + @Override + public boolean wasMade() { + return action.isClaimed(); + } + + @Override + public String author() { + return action.getClaimedByName(); + } + + @Override + public String reason() { + return action.getReason(); + } + + public String toString() { + return String.format("Claimed by \"%s\": \"%s\"", author(), reason()); + } +} diff --git a/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/NotClaimed.java b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/NotClaimed.java new file mode 100644 index 000000000..b6b68ae0c --- /dev/null +++ b/src/main/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/NotClaimed.java @@ -0,0 +1,22 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim; + +public class NotClaimed implements Claim { + @Override + public boolean wasMade() { + return false; + } + + @Override + public String author() { + return null; + } + + @Override + public String reason() { + return null; + } + + public String toString() { + return "Not claimed"; + } +} diff --git a/src/main/resources/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView/main-jobViews.jelly b/src/main/resources/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView/main-jobViews.jelly index f4f486976..e5e99108a 100644 --- a/src/main/resources/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView/main-jobViews.jelly +++ b/src/main/resources/com/smartcodeltd/jenkinsci/plugins/buildmonitor/BuildMonitorView/main-jobViews.jelly @@ -13,6 +13,9 @@ <a title="{{job.name}}" href="{{job.url}}">{{job.name}}</a> </h2> + <ul class="description"> + <li data-ng-show="job.claimed">Claimed by <strong>{{ job.claimAuthor }}</strong>: {{ job.claimReason }}</li> + </ul> <ul data-ng-show="job.culprits.size() > 0" class="culprits"> <li data-ng-repeat="name in job.culprits"> {{name}} diff --git a/src/main/webapp/themes/industrial.css b/src/main/webapp/themes/industrial.css index 549225f90..bebd41590 100644 --- a/src/main/webapp/themes/industrial.css +++ b/src/main/webapp/themes/industrial.css @@ -97,7 +97,8 @@ h2 { } .build-monitor .successful { background-color:darkgreen; } -.build-monitor .failing { background-color:darkred; } +.build-monitor .failing { background-color:darkred; } +.build-monitor .claimed { background-color: #fe5e00; } .build-monitor #job-views .build-time, .build-monitor #job-views .build-name { @@ -121,11 +122,16 @@ h2 { } -.build-monitor ul.culprits, .build-monitor ol { +.build-monitor .latest-results ul, +.build-monitor .latest-results ol { list-style-type: none; margin: 0 0 0.25em 1em; padding: 0; font-size: 1.2em; } +.build-monitor ul#job-views .claimed .meta ul.culprits li { + font-size: 1em; + margin-top:0.5em; +} .build-monitor .meta li { display: inline-block; } .build-monitor .meta .culprits li { margin-right:0.5em; } @@ -303,8 +309,14 @@ h2 { background-color: firebrick; } +.build-monitor ul#job-views .claimed > .progress { + -webkit-animation: forClaimed 2.25s 2 alternate; + background-color: #fe7600; +} + @-webkit-keyframes forSuccessful { 0% {background-color: green;} 100% {background-color: limegreen;} } @-webkit-keyframes forFailing { 0% {background-color: firebrick;} 100% {background-color: red;} } +@-webkit-keyframes forClaimed { 0% {background-color: #fe7600; } 100% { background-color: orange; } } /* * Modal diff --git a/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobViewTest.java b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobViewTest.java index 0c5b3a0e7..1e72b8c40 100644 --- a/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobViewTest.java +++ b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/JobViewTest.java @@ -1,5 +1,8 @@ package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.Augmentation; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.BuildAugmentor; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.Claim; import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.BuildStateRecipe; import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.JobStateRecipe; import hudson.model.Job; @@ -9,8 +12,7 @@ import java.text.ParseException; import java.text.SimpleDateFormat; -import java.util.Date; -import java.util.List; +import java.util.*; import static com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.Loops.asFollows; import static com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.TimeMachine.assumeThat; @@ -18,7 +20,8 @@ import static hudson.model.Result.*; import static org.hamcrest.CoreMatchers.hasItems; import static org.hamcrest.CoreMatchers.not; -import static org.hamcrest.Matchers.*; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.hasItem; import static org.hamcrest.collection.IsCollectionWithSize.hasSize; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; @@ -292,7 +295,17 @@ public void should_describe_the_job_as_failing_when_there_are_several_builds_run assertThat(view.status(), containsString("failing")); } - + + @Test + public void should_describe_the_job_as_claimed_if_someone_claimed_last_build_failures() { + view = JobView.of( + a(job().whereTheLast(build().finishedWith(FAILURE).andWasClaimedBy("Adam", "sorry, I broke it, fixing now"))), + augmentedWith(Claim.class) + ); + + assertThat(view.status(), containsString("claimed")); + } + /* * Should produce some basic build statistics */ @@ -370,6 +383,25 @@ public void should_know_the_authors_of_commits_that_made_it_into_the_build() { // } } + /* + * Should know who claimed a broken build + */ + + @Test + public void should_know_if_a_failing_build_has_been_claimed() throws Exception { + String ourPotentialHero = "Adam", + theReason = "I broke it, sorry, fixing now"; + + view = JobView.of( + a(job().whereTheLast(build().finishedWith(FAILURE).andWasClaimedBy(ourPotentialHero, theReason))), + augmentedWith(Claim.class) + ); + + assertThat(view.isClaimed(), is(true)); + assertThat(view.claimAuthor(), is(ourPotentialHero)); + assertThat(view.claimReason(), is(theReason)); + } + @Test public void public_api_should_return_reasonable_defaults_for_jobs_that_never_run() throws Exception { view = JobView.of(a(job().thatHasNeverRun())); @@ -381,6 +413,7 @@ public void public_api_should_return_reasonable_defaults_for_jobs_that_never_run assertThat(view.progress(), is(0)); assertThat(view.culprits(), hasSize(0)); assertThat(view.status(), is("failing")); + assertThat(view.isClaimed(), is(false)); } /* @@ -407,4 +440,14 @@ private Date assumingThatCurrentTimeIs(String currentTime) throws ParseException return systemTime; } + + private <T extends Augmentation> BuildAugmentor augmentedWith(Class<T>... augmentationsToSupport) { + BuildAugmentor augmentor = new BuildAugmentor(); + + for (Class<T> augmentation : augmentationsToSupport) { + augmentor.support(augmentation); + } + + return augmentor; + } } \ No newline at end of file diff --git a/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/BuildAugmentorTest.java b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/BuildAugmentorTest.java new file mode 100644 index 000000000..fb3091e72 --- /dev/null +++ b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/BuildAugmentorTest.java @@ -0,0 +1,53 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins; + +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.Claim; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.Claimed; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim.NotClaimed; +import com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.syntacticsugar.BuildStateRecipe; +import hudson.model.Result; +import hudson.model.Run; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class BuildAugmentorTest { + private BuildAugmentor augmentor = new BuildAugmentor(); + private final String AUTHOR = "Adam"; + private final String REASON = "Sorry, I broke it, fixing now"; + + private Run<?, ?> unclaimedBuild = a(build()); + private Run<?, ?> claimedBuild = a(build().finishedWith(Result.FAILURE).andWasClaimedBy(AUTHOR, REASON)); + + @Test + public void should_recognise_any_build_as_not_claimed_by_default() { + assertThat(augmentor.detailsOf(unclaimedBuild, Claim.class), instanceOf(NotClaimed.class)); + assertThat(augmentor.detailsOf(claimedBuild, Claim.class), instanceOf(NotClaimed.class)); + } + + @Test + public void should_recognise_a_claimed_build_once_you_ask_him_to_do_it() throws Exception { + augmentor.support(Claim.class); + + Claim claim = augmentor.detailsOf(claimedBuild, Claim.class); + + assertThat(claim, instanceOf(Claimed.class)); + + assertThat(claim.wasMade(), is(true)); + assertThat(claim.author(), is(AUTHOR)); + assertThat(claim.reason(), is(REASON)); + } + + /* + * Syntactic sugar + */ + + private Run<?, ?> a(BuildStateRecipe recipe) { + return recipe.execute(); + } + + private BuildStateRecipe build() { + return new BuildStateRecipe(); + } +} \ No newline at end of file diff --git a/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/ClaimedTest.java b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/ClaimedTest.java new file mode 100644 index 000000000..31c51e17b --- /dev/null +++ b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/ClaimedTest.java @@ -0,0 +1,35 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim; + +import hudson.plugins.claim.ClaimBuildAction; +import org.junit.Test; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; + +public class ClaimedTest { + private final static String AUTHOR = "Adam"; + private final static String REASON = "I broke it, sorry, fixing now."; + private final static String EXPECTED_STRING_REPRESENTATION = String.format("Claimed by \"%s\": \"%s\"", AUTHOR, REASON); + + @Test + public void should_be_a_simple_proxy_to_the_claim_build_action() throws Exception { + Claim claim = new Claimed(action()); + + assertThat(claim.wasMade(), is(true)); + assertThat(claim.author(), is(AUTHOR)); + assertThat(claim.reason(), is(REASON)); + + assertThat(claim.toString(), is(EXPECTED_STRING_REPRESENTATION)); + } + + private ClaimBuildAction action() { + ClaimBuildAction action = mock(ClaimBuildAction.class); + when(action.isClaimed()).thenReturn(true); + when(action.getClaimedByName()).thenReturn(AUTHOR); + when(action.getReason()).thenReturn(REASON); + + return action; + } +} \ No newline at end of file diff --git a/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/NotClaimedTest.java b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/NotClaimedTest.java new file mode 100644 index 000000000..3f2cde1d5 --- /dev/null +++ b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/plugins/claim/NotClaimedTest.java @@ -0,0 +1,20 @@ +package com.smartcodeltd.jenkinsci.plugins.buildmonitor.viewmodel.plugins.claim; + +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.nullValue; +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +public class NotClaimedTest { + @Test + public void should_provide_sensible_defaults_if_the_build_is_not_claimed_or_the_claim_plugin_is_not_installed() throws Exception { + Claim claim = new NotClaimed(); + + assertThat(claim.toString(), is("Not claimed")); + + assertThat(claim.wasMade(), is(false)); + assertThat(claim.author(), is(nullValue())); + assertThat(claim.reason(), is(nullValue())); + } +} diff --git a/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/syntacticsugar/BuildStateRecipe.java b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/syntacticsugar/BuildStateRecipe.java index 02dab9a2d..9504e4742 100644 --- a/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/syntacticsugar/BuildStateRecipe.java +++ b/src/test/java/com/smartcodeltd/jenkinsci/plugins/buildmonitor/viewmodel/syntacticsugar/BuildStateRecipe.java @@ -3,6 +3,7 @@ import hudson.model.AbstractBuild; import hudson.model.Result; import hudson.model.User; +import hudson.plugins.claim.ClaimBuildAction; import hudson.scm.ChangeLogSet; import java.text.SimpleDateFormat; @@ -118,6 +119,18 @@ public BuildStateRecipe andUsuallyTakes(int minutes) throws Exception{ return this; } + public BuildStateRecipe andWasClaimedBy(String aPotentialHero, String reason) { + final ClaimBuildAction claim = mock(ClaimBuildAction.class); + + when(claim.isClaimed()).thenReturn(true); + when(claim.getClaimedByName()).thenReturn(aPotentialHero); + when(claim.getReason()).thenReturn(reason); + + when(build.getAction(ClaimBuildAction.class)).thenReturn(claim); + + return this; + } + public AbstractBuild execute() { return build; }