1 package org.kuali.common.devops.jenkins.upgrade.model;
2
3 import static com.google.common.base.Optional.absent;
4 import static com.google.common.base.Preconditions.checkNotNull;
5 import static com.google.common.collect.Iterables.filter;
6 import static com.google.common.collect.Lists.newArrayList;
7 import static com.google.common.collect.Ordering.natural;
8 import static java.lang.String.format;
9 import static org.kuali.common.core.io.Files.buildUnixFile;
10 import static org.kuali.common.core.io.Files.checkIsDir;
11 import static org.kuali.common.devops.jenkins.upgrade.Jenkins.BUILDS_DIRECTORY;
12 import static org.kuali.common.devops.jenkins.upgrade.Jenkins.buildNumberMap;
13 import static org.kuali.common.devops.jenkins.upgrade.Jenkins.isJenkinsBuildDirectory;
14 import static org.kuali.common.devops.jenkins.upgrade.Jenkins.listBuildDirContents;
15 import static org.kuali.common.util.base.Precondition.checkNotBlank;
16 import static org.kuali.common.util.base.Precondition.checkNotNull;
17 import static org.kuali.common.util.log.Loggers.newLogger;
18
19 import java.io.IOException;
20 import java.nio.file.Path;
21 import java.nio.file.Paths;
22 import java.util.List;
23 import java.util.Map;
24
25 import org.kuali.common.core.io.UnixFile;
26 import org.slf4j.Logger;
27
28 import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
29 import com.google.common.base.Optional;
30 import com.google.common.base.Predicate;
31 import com.google.common.collect.ImmutableList;
32
33 @JsonDeserialize(builder = JobSummary.Builder.class)
34 public final class JobSummary {
35
36 private static final Logger logger = newLogger();
37
38 private final String name;
39 private final UnixFile basedir;
40 private final ImmutableList<BuildSummary> builds;
41 private final Optional<BuildSummary> lastFailedBuild;
42 private final Optional<BuildSummary> lastStableBuild;
43 private final Optional<BuildSummary> lastSuccessfulBuild;
44 private final Optional<BuildSummary> lastUnstableBuild;
45 private final Optional<BuildSummary> lastUnsuccessfulBuild;
46
47 public static JobSummary build(UnixFile basedir, String timeZoneId, long startedBefore) throws IOException {
48 checkIsDir(basedir);
49 List<UnixFile> files = listBuildDirContents(basedir);
50 Map<String, Integer> buildNumbers = buildNumberMap(files);
51 List<BuildSummary> builds = getBuilds(files, buildNumbers, timeZoneId, startedBefore);
52 String name = basedir.getFileName();
53 Builder builder = builder().withBasedir(basedir).withBuilds(builds).withName(name);
54 builder.withLastFailedBuild(getNamedBuild(basedir, "lastFailedBuild", builds));
55 builder.withLastStableBuild(getNamedBuild(basedir, "lastStableBuild", builds));
56 builder.withLastSuccessfulBuild(getNamedBuild(basedir, "lastSuccessfulBuild", builds));
57 builder.withLastUnstableBuild(getNamedBuild(basedir, "lastUnstableBuild", builds));
58 builder.withLastUnsuccessfulBuild(getNamedBuild(basedir, "lastUnsuccessfulBuild", builds));
59 return builder.build();
60 }
61
62 private static Optional<BuildSummary> getNamedBuild(UnixFile jobDir, String link, List<BuildSummary> builds) {
63 try {
64 Path path = Paths.get(jobDir.getPath() + "/" + BUILDS_DIRECTORY + "/" + link);
65 UnixFile file = buildUnixFile(path);
66 if (!file.getAttributes().isSymbolicLink()) {
67 return absent();
68 }
69 Path realPath = path.toRealPath();
70 UnixFile realFile = buildUnixFile(realPath);
71 for (BuildSummary build : builds) {
72 if (realFile.equals(build.getBasedir())) {
73 return Optional.of(build);
74 }
75 }
76 return absent();
77 } catch (IOException e) {
78 return absent();
79 }
80 }
81
82 private static List<BuildSummary> getBuilds(List<UnixFile> files, Map<String, Integer> buildNumbers, String timeZoneId, long startedBefore) throws IOException {
83
84 Predicate<UnixFile> buildsOnly = isJenkinsBuildDirectory();
85
86
87 List<UnixFile> list = natural().sortedCopy(filter(files, buildsOnly));
88
89
90 List<BuildSummary> builds = newArrayList();
91 for (UnixFile element : list) {
92 try {
93 int buildNumber = checkNotNull(buildNumbers.get(element.getPath()), "no build number for [%s]", element.getPath());
94 BuildSummary build = BuildSummary.build(element, buildNumber, timeZoneId);
95 if (build.getStartTime() > startedBefore) {
96 continue;
97 }
98 if (!build.getFiles().isEmpty()) {
99 builds.add(build);
100 }
101 } catch (IOException e) {
102
103
104 logger.info(format("error -> [%s]", e));
105 }
106 }
107 return builds;
108 }
109
110 public static Builder builder() {
111 return new Builder();
112 }
113
114 private JobSummary(Builder builder) {
115 this.name = builder.name;
116 this.basedir = builder.basedir;
117 this.builds = ImmutableList.copyOf(builder.builds);
118 this.lastFailedBuild = builder.lastFailedBuild;
119 this.lastStableBuild = builder.lastStableBuild;
120 this.lastSuccessfulBuild = builder.lastSuccessfulBuild;
121 this.lastUnstableBuild = builder.lastUnstableBuild;
122 this.lastUnsuccessfulBuild = builder.lastUnsuccessfulBuild;
123 }
124
125 public static class Builder implements org.apache.commons.lang3.builder.Builder<JobSummary> {
126
127 private String name;
128 private UnixFile basedir;
129 private List<BuildSummary> builds = newArrayList();
130 private Optional<BuildSummary> lastFailedBuild = absent();
131 private Optional<BuildSummary> lastStableBuild = absent();
132 private Optional<BuildSummary> lastSuccessfulBuild = absent();
133 private Optional<BuildSummary> lastUnstableBuild = absent();
134 private Optional<BuildSummary> lastUnsuccessfulBuild = absent();
135
136 public Builder withLastUnsuccessfulBuild(Optional<BuildSummary> lastUnsuccessfulBuild) {
137 this.lastUnsuccessfulBuild = lastUnsuccessfulBuild;
138 return this;
139 }
140
141 public Builder withLastUnstableBuild(Optional<BuildSummary> lastUnstableBuild) {
142 this.lastUnstableBuild = lastUnstableBuild;
143 return this;
144 }
145
146 public Builder withLastSuccessfulBuild(Optional<BuildSummary> lastSuccessfulBuild) {
147 this.lastSuccessfulBuild = lastSuccessfulBuild;
148 return this;
149 }
150
151 public Builder withLastStableBuild(Optional<BuildSummary> lastStableBuild) {
152 this.lastStableBuild = lastStableBuild;
153 return this;
154 }
155
156 public Builder withLastFailedBuild(Optional<BuildSummary> lastFailedBuild) {
157 this.lastFailedBuild = lastFailedBuild;
158 return this;
159 }
160
161 public Builder withBasedir(UnixFile basedir) {
162 this.basedir = basedir;
163 return this;
164 }
165
166 public Builder withName(String name) {
167 this.name = name;
168 return this;
169 }
170
171 public Builder withBuilds(List<BuildSummary> builds) {
172 this.builds = builds;
173 return this;
174 }
175
176 @Override
177 public JobSummary build() {
178 return validate(new JobSummary(this));
179 }
180
181 private static JobSummary validate(JobSummary instance) {
182 checkNotBlank(instance.name, "name");
183 checkNotNull(instance.basedir, "basedir");
184 checkNotNull(instance.builds, "builds");
185 return instance;
186 }
187 }
188
189 public List<BuildSummary> getBuilds() {
190 return builds;
191 }
192
193 public String getName() {
194 return name;
195 }
196
197 public UnixFile getBasedir() {
198 return basedir;
199 }
200
201 public Optional<BuildSummary> getLastFailedBuild() {
202 return lastFailedBuild;
203 }
204
205 public Optional<BuildSummary> getLastStableBuild() {
206 return lastStableBuild;
207 }
208
209 public Optional<BuildSummary> getLastSuccessfulBuild() {
210 return lastSuccessfulBuild;
211 }
212
213 public Optional<BuildSummary> getLastUnstableBuild() {
214 return lastUnstableBuild;
215 }
216
217 public Optional<BuildSummary> getLastUnsuccessfulBuild() {
218 return lastUnsuccessfulBuild;
219 }
220
221 }