diff --git a/ci-eye.iml b/ci-eye.iml index 48c61c6..da19e6d 100644 --- a/ci-eye.iml +++ b/ci-eye.iml @@ -9,8 +9,8 @@ - - + + diff --git a/src/main/java/org/netmelody/cieye/core/utility/ProjectAbbreviator.java b/src/main/java/org/netmelody/cieye/core/utility/ProjectAbbreviator.java new file mode 100644 index 0000000..b8ec8dd --- /dev/null +++ b/src/main/java/org/netmelody/cieye/core/utility/ProjectAbbreviator.java @@ -0,0 +1,24 @@ +package org.netmelody.cieye.core.utility; + +import java.util.regex.Pattern; + +public class ProjectAbbreviator { + + public String abbreviate(String projectName) { + StringBuilder out = new StringBuilder(); + String[] nameParts = Pattern.compile("[-\\s]+").split(projectName); + if (nameParts.length == 1) { + return projectName; + } else { + for (String s : nameParts) { + out.append(s.charAt(0)); + } + return out.toString(); + } + } + + + public static String nameWithProjectAbbreviation(String projectName, String buildName) { + return new ProjectAbbreviator().abbreviate(projectName) + ": " + buildName; + } +} \ No newline at end of file diff --git a/src/main/java/org/netmelody/cieye/server/observation/IntelligenceAgency.java b/src/main/java/org/netmelody/cieye/server/observation/IntelligenceAgency.java index 940856d..7157acb 100644 --- a/src/main/java/org/netmelody/cieye/server/observation/IntelligenceAgency.java +++ b/src/main/java/org/netmelody/cieye/server/observation/IntelligenceAgency.java @@ -70,6 +70,7 @@ private PollingSpyHandler spyFor(Feature feature) { private PollingSpyHandler createSpyFor(Feature feature) { final ObservationAgency agency = foreignAgencies.agencyFor(feature.type()); final CiSpy spy = agency.provideSpyFor(feature, network, directory); + agencies.put(feature.type(), agency); return new PollingSpyHandler(spy, feature); } diff --git a/src/main/java/org/netmelody/cieye/spies/teamcity/BuildTypeAnalyser.java b/src/main/java/org/netmelody/cieye/spies/teamcity/BuildTypeAnalyser.java index 8da3da3..8564933 100644 --- a/src/main/java/org/netmelody/cieye/spies/teamcity/BuildTypeAnalyser.java +++ b/src/main/java/org/netmelody/cieye/spies/teamcity/BuildTypeAnalyser.java @@ -1,24 +1,19 @@ package org.netmelody.cieye.spies.teamcity; -import static org.netmelody.cieye.core.domain.Percentage.percentageOf; +import org.netmelody.cieye.core.domain.RunningBuild; +import org.netmelody.cieye.core.domain.Sponsor; +import org.netmelody.cieye.core.domain.Status; +import org.netmelody.cieye.core.domain.TargetDetail; +import org.netmelody.cieye.core.observation.KnownOffendersDirectory; +import org.netmelody.cieye.spies.teamcity.jsondomain.*; import java.util.ArrayList; import java.util.HashSet; import java.util.List; import java.util.Set; -import org.netmelody.cieye.core.domain.RunningBuild; -import org.netmelody.cieye.core.domain.Sponsor; -import org.netmelody.cieye.core.domain.Status; -import org.netmelody.cieye.core.domain.TargetDetail; -import org.netmelody.cieye.core.observation.KnownOffendersDirectory; -import org.netmelody.cieye.spies.teamcity.jsondomain.Build; -import org.netmelody.cieye.spies.teamcity.jsondomain.BuildDetail; -import org.netmelody.cieye.spies.teamcity.jsondomain.BuildType; -import org.netmelody.cieye.spies.teamcity.jsondomain.BuildTypeDetail; -import org.netmelody.cieye.spies.teamcity.jsondomain.Change; -import org.netmelody.cieye.spies.teamcity.jsondomain.ChangeDetail; -import org.netmelody.cieye.spies.teamcity.jsondomain.Investigation; +import static org.netmelody.cieye.core.domain.Percentage.percentageOf; +import static org.netmelody.cieye.core.utility.ProjectAbbreviator.nameWithProjectAbbreviation; public final class BuildTypeAnalyser { @@ -29,12 +24,12 @@ public BuildTypeAnalyser(TeamCityCommunicator communicator, KnownOffendersDirect this.communicator = communicator; this.detective = detective; } - + public TargetDetail targetFrom(BuildType buildType) { final BuildTypeDetail buildTypeDetail = communicator.detailsFor(buildType); - if (buildTypeDetail.paused) { - return new TargetDetail(communicator.endpoint() + buildType.href, buildType.webUrl(), buildType.name, Status.DISABLED, 0L); + if (buildTypeDetail.paused || buildTypeDetail.externalStatusDisabled()) { + return new TargetDetail(communicator.endpoint() + buildType.href, buildType.webUrl(), nameWithProjectAbbreviation(buildType.projectName, buildType.name), Status.DISABLED, 0L); } final Set sponsors = new HashSet(); @@ -67,7 +62,7 @@ public TargetDetail targetFrom(BuildType buildType) { } } - return new TargetDetail(communicator.endpoint() + buildType.href, buildType.webUrl(), buildType.name, currentStatus, startTime, runningBuilds, sponsors); + return new TargetDetail(communicator.endpoint() + buildType.href, buildType.webUrl(), nameWithProjectAbbreviation(buildType.projectName, buildType.name), currentStatus, startTime, runningBuilds, sponsors); } private Set sponsorsOf(BuildDetail build) { diff --git a/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCityCommunicator.java b/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCityCommunicator.java index b592ea3..5864a79 100644 --- a/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCityCommunicator.java +++ b/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCityCommunicator.java @@ -37,7 +37,7 @@ public final class TeamCityCommunicator { public TeamCityCommunicator(Contact contact, String endpoint) { this.contact = contact; this.endpoint = endpoint; - this.prefix = (contact.privileged() ? "/httpAuth" : "/guestAuth") + "/app/rest"; + this.prefix = (contact.privileged() ? "/httpAuth" : "/guestAuth") + "/app/rest/7.0"; } public String endpoint() { @@ -91,18 +91,18 @@ public void commentOn(Build lastCompletedBuild, String note) { public List changesOf(BuildDetail buildDetail) { final JsonElement json = contact.makeJsonRestCall(endpoint + buildDetail.changes.href); final JsonElement change = json.isJsonObject() ? json.getAsJsonObject().get("change") : JsonNull.INSTANCE; - + if (null == change || !(change.isJsonArray() || change.isJsonObject())) { return ImmutableList.of(); } - + final Gson gson = new Gson(); final List changes = new ArrayList(); final Iterable changesJson = change.isJsonArray() ? change.getAsJsonArray() : ImmutableList.of(change); for (JsonElement jsonElement : changesJson) { changes.add(gson.fromJson(jsonElement, Change.class)); } - + return changes; } diff --git a/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCitySpy.java b/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCitySpy.java index ce29aac..8222ab0 100644 --- a/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCitySpy.java +++ b/src/main/java/org/netmelody/cieye/spies/teamcity/TeamCitySpy.java @@ -4,6 +4,7 @@ import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Maps.newHashMap; import static org.netmelody.cieye.core.domain.Status.UNKNOWN; +import static org.netmelody.cieye.core.utility.ProjectAbbreviator.nameWithProjectAbbreviation; import java.util.Collection; import java.util.List; @@ -42,7 +43,7 @@ public TargetDigestGroup targetsConstituting(Feature feature) { final List digests = newArrayList(); for (BuildType buildType : buildTypes) { - final TargetDigest targetDigest = new TargetDigest(communicator.endpoint() + buildType.href, buildType.webUrl(), buildType.name, UNKNOWN); + final TargetDigest targetDigest = new TargetDigest(communicator.endpoint() + buildType.href, buildType.webUrl(), nameWithProjectAbbreviation(buildType.projectName, buildType.name), UNKNOWN); digests.add(targetDigest); recognisedBuildTypes.put(targetDigest.id(), buildType); } diff --git a/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettings.java b/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettings.java new file mode 100644 index 0000000..3230832 --- /dev/null +++ b/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettings.java @@ -0,0 +1,28 @@ +package org.netmelody.cieye.spies.teamcity.jsondomain; + +import com.google.common.base.Optional; +import com.google.common.base.Predicate; +import com.google.common.collect.Iterables; + +import java.util.List; + +import static java.lang.Boolean.parseBoolean; + +public class BuildSettings { + public List property; + + public boolean externalStatusDisabled() { + Optional allowExternalStatus = Iterables.tryFind(property, new Predicate() { + @Override + public boolean apply(BuildSettingsProperty input) { + return "allowExternalStatus".equals(input.name); + } + }); + + if (allowExternalStatus.isPresent()) { + return !Boolean.parseBoolean(allowExternalStatus.get().value); + } else { + return false; + } + } +} diff --git a/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettingsProperty.java b/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettingsProperty.java new file mode 100644 index 0000000..1918b63 --- /dev/null +++ b/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettingsProperty.java @@ -0,0 +1,6 @@ +package org.netmelody.cieye.spies.teamcity.jsondomain; + +public class BuildSettingsProperty { + public String name; + public String value; +} diff --git a/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildTypeDetail.java b/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildTypeDetail.java index 9aedce0..d0b1121 100644 --- a/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildTypeDetail.java +++ b/src/main/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildTypeDetail.java @@ -6,6 +6,11 @@ public final class BuildTypeDetail extends BuildType { public boolean paused; public Project project; public BuildsHref builds; + public BuildSettings settings; + + public boolean externalStatusDisabled() { + return settings != null && settings.externalStatusDisabled(); + } //vcs-root //parameters //runParameters diff --git a/src/main/webapp/resources/cieye.js b/src/main/webapp/resources/cieye.js index 4efc4fc..be1718b 100644 --- a/src/main/webapp/resources/cieye.js +++ b/src/main/webapp/resources/cieye.js @@ -280,11 +280,19 @@ ORG.NETMELODY.CIEYE.newRadiatorWidget = function() { } var result = true; - $.each(targetsJson, function(index, targetJson) { - if (targetJson.builds.length !== 0 || (targetJson.status !== "GREEN" && targetJson.status !== "DISABLED")) { + $.each(targetsJson, function(i, targetJson) { + if (targetJson.status !== "GREEN" && targetJson.status !== "DISABLED") { result = false; return false; } + if (targetJson.builds.length > 0) { + $.each(targetJson.builds, function (i2, build) { + if (build.status !== "GREEN") { + result = false; + return false; + } + }); + } }); return result; } diff --git a/src/test/java/org/netmelody/cieye/core/utility/ProjectAbbreviatorTest.java b/src/test/java/org/netmelody/cieye/core/utility/ProjectAbbreviatorTest.java new file mode 100644 index 0000000..5d58efb --- /dev/null +++ b/src/test/java/org/netmelody/cieye/core/utility/ProjectAbbreviatorTest.java @@ -0,0 +1,24 @@ +package org.netmelody.cieye.core.utility; + +import org.junit.Assert; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.equalTo; + +public class ProjectAbbreviatorTest { + + @Test + public void doesNotAbbreviateIfNoSpaceInName() throws Throwable { + Assert.assertThat("myProjectName", equalTo(new ProjectAbbreviator().abbreviate("myProjectName"))); + } + + @Test + public void abbreviatesToFirstLettersOfWordsIfThereAreSpaces() throws Throwable { + Assert.assertThat("MpN", equalTo(new ProjectAbbreviator().abbreviate("My project Name"))); + } + + @Test + public void abbreviatesToFirstLettersOfWordsIfThereAreHyphens() throws Throwable { + Assert.assertThat("MpNh", equalTo(new ProjectAbbreviator().abbreviate("My-project Name-hyphens"))); + } +} \ No newline at end of file diff --git a/src/test/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettingsTest.java b/src/test/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettingsTest.java new file mode 100644 index 0000000..c48187f --- /dev/null +++ b/src/test/java/org/netmelody/cieye/spies/teamcity/jsondomain/BuildSettingsTest.java @@ -0,0 +1,41 @@ +package org.netmelody.cieye.spies.teamcity.jsondomain; + +import org.junit.Test; + +import static com.google.common.collect.Lists.newArrayList; +import static org.hamcrest.CoreMatchers.equalTo; +import static org.junit.Assert.assertThat; + +public class BuildSettingsTest { + + @Test + public void isDisabledWhenAllowExternalStatusIsFalse() { + BuildSettings buildSettings = createBuildSettingsWithAllowExternalStatus("false"); + + assertThat(buildSettings.externalStatusDisabled(), equalTo(true)); + } + + @Test + public void isNotDisabledWhenAllowExternalStatusIsTrue() { + BuildSettings buildSettings = createBuildSettingsWithAllowExternalStatus("true"); + + assertThat(buildSettings.externalStatusDisabled(), equalTo(false)); + } + + @Test + public void isNotDisabledWhenAllowExternalStatusIsNotPresent() { + BuildSettings buildSettings = new BuildSettings(); + buildSettings.property = newArrayList(); + + assertThat(buildSettings.externalStatusDisabled(), equalTo(false)); + } + + private BuildSettings createBuildSettingsWithAllowExternalStatus(String allowExternalStatus) { + BuildSettings buildSettings = new BuildSettings(); + final BuildSettingsProperty property = new BuildSettingsProperty(); + property.name = "allowExternalStatus"; + property.value = allowExternalStatus; + buildSettings.property = newArrayList(property); + return buildSettings; + } +}