1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package com.atlassian.theplugin.idea.bamboo;
18
19 import com.atlassian.theplugin.commons.bamboo.*;
20 import com.atlassian.theplugin.commons.exception.ServerPasswordNotProvidedException;
21 import com.atlassian.theplugin.commons.remoteapi.RemoteApiException;
22 import com.atlassian.theplugin.configuration.ProjectConfigurationBean;
23 import com.atlassian.theplugin.configuration.ProjectToolWindowTableConfiguration;
24 import com.atlassian.theplugin.idea.ui.AbstractTableToolWindowPanel;
25 import com.atlassian.theplugin.idea.ui.TableColumnProvider;
26 import com.atlassian.theplugin.idea.util.memoryvfs.PlainTextMemoryVirtualFile;
27 import com.atlassian.theplugin.util.PluginUtil;
28 import com.intellij.ide.BrowserUtil;
29 import com.intellij.openapi.fileEditor.FileEditorManager;
30 import com.intellij.openapi.project.Project;
31 import com.intellij.util.ui.UIUtil;
32 import org.joda.time.format.DateTimeFormat;
33 import org.joda.time.format.DateTimeFormatter;
34
35 import javax.swing.*;
36 import java.util.ArrayList;
37 import java.util.Collection;
38 import java.util.Date;
39 import java.util.List;
40
41 public class BambooTableToolWindowPanel extends AbstractTableToolWindowPanel<BambooBuildAdapterIdea>
42 implements BambooStatusListener {
43 private final transient BambooServerFacade bambooFacade;
44 private static final DateTimeFormatter TIME_DF = DateTimeFormat.forPattern("hh:mm a");
45 private TableColumnProvider columnProvider;
46 private final TestResultsToolWindow testResultsToolWindow;
47 private final BuildChangesToolWindow buildChangesToolWindow;
48 public static final String BAMBOO_ATLASSIAN_TOOLWINDOW_SERVER_TOOL_BAR = "atlassian.bamboo.toolwindow";
49
50 @Override
51 protected String getInitialMessage() {
52 return "Waiting for Bamboo statuses.";
53 }
54
55 @Override
56 protected String getToolbarActionGroup() {
57 return "ThePlugin.BambooToolWindowToolBar";
58 }
59
60 @Override
61 protected String getPopupActionGroup() {
62 return "ThePlugin.Bamboo.BuildPopupMenu";
63 }
64
65 @Override
66 protected TableColumnProvider getTableColumnProvider() {
67 if (columnProvider == null) {
68 columnProvider = new BambooTableColumnProviderImpl();
69 }
70 return columnProvider;
71 }
72
73 @Override
74 protected ProjectToolWindowTableConfiguration getTableConfiguration() {
75 return projectConfiguration.getBambooConfiguration().getTableConfiguration();
76 }
77
78 @Override
79 public void applyAdvancedFilter() {
80 }
81
82 @Override
83 public void cancelAdvancedFilter() {
84 }
85
86 @Override
87 public void clearAdvancedFilter() {
88 }
89
90 @Override
91 public String getActionPlace() {
92 return BAMBOO_ATLASSIAN_TOOLWINDOW_SERVER_TOOL_BAR + project.getName();
93 }
94
95 public BambooTableToolWindowPanel(Project project, ProjectConfigurationBean projectConfigurationBean,
96 final TestResultsToolWindow testResultsToolWindow, final BuildChangesToolWindow buildChangesToolWindow) {
97 super(project, projectConfigurationBean);
98 this.testResultsToolWindow = testResultsToolWindow;
99 this.buildChangesToolWindow = buildChangesToolWindow;
100 bambooFacade = BambooServerFacadeImpl.getInstance(PluginUtil.getLogger());
101
102 assert this.testResultsToolWindow != null;
103
104 assert this.buildChangesToolWindow != null;
105 }
106
107
108 @Override
109 protected void handlePopupClick(Object selectedObject) {
110 }
111
112 @Override
113 protected void handleDoubleClick(Object selectedObject) {
114 BambooBuildAdapter build = (BambooBuildAdapter) selectedObject;
115 if (build != null) {
116 BrowserUtil.launchBrowser(build.getBuildResultUrl());
117 }
118 }
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133 private void openLabelDialog(BambooBuildAdapterIdea build) {
134 BuildLabelForm buildLabelForm = new BuildLabelForm(build);
135 buildLabelForm.show();
136 if (buildLabelForm.getExitCode() == 0) {
137 labelBuild(build, buildLabelForm.getLabel());
138 }
139 }
140
141 private void labelBuild(final BambooBuildAdapterIdea build, final String label) {
142 new Thread(new Runnable() {
143 public void run() {
144 setStatusMessage("Applying label on build...");
145 try {
146 bambooFacade.addLabelToBuild(build.getServer(),
147 build.getBuildKey(), build.getBuildNumber(), label);
148 setStatusMessage("Label applied on build");
149 } catch (ServerPasswordNotProvidedException e) {
150 setStatusMessage("Label not applied: Password on provided for server");
151 } catch (RemoteApiException e) {
152 setStatusMessage("Label not applied: " + e.getMessage());
153 }
154 }
155 }, "atlassian-idea-plugin label build").start();
156 }
157
158 public void addLabelToBuild() {
159 BambooBuildAdapterIdea build = table.getSelectedObject();
160 openLabelDialog(build);
161 }
162
163 private void openCommentDialog(BambooBuildAdapterIdea build) {
164 BuildCommentForm buildCommentForm = new BuildCommentForm(build);
165 buildCommentForm.show();
166 if (buildCommentForm.getExitCode() == 0) {
167 commentBuild(build, buildCommentForm.getCommentText());
168 }
169 }
170
171 private void commentBuild(final BambooBuildAdapterIdea build, final String commentText) {
172 new Thread(new Runnable() {
173 public void run() {
174 setStatusMessage("Adding comment label on build...");
175 try {
176 bambooFacade.addCommentToBuild(build.getServer(),
177 build.getBuildKey(), build.getBuildNumber(), commentText);
178 setStatusMessage("Comment added to build");
179 } catch (ServerPasswordNotProvidedException e) {
180 setStatusMessage("Comment not added: Password not provided for server");
181 } catch (RemoteApiException e) {
182 setStatusMessage("Comment not added: " + e.getMessage());
183 }
184
185 }
186 }, "atlassian-idea-plugin comment build").start();
187 }
188
189 public void addCommentToBuild() {
190 BambooBuildAdapterIdea build = table.getSelectedObject();
191 openCommentDialog(build);
192 }
193
194 private void executeBuild(final BambooBuildAdapterIdea build) {
195 new Thread(new Runnable() {
196 public void run() {
197 setStatusMessage("Executing build on plan " + build.getBuildKey());
198 try {
199 bambooFacade.executeBuild(build.getServer(), build.getBuildKey());
200 setStatusMessage("Build executed on plan: " + build.getBuildKey());
201 } catch (ServerPasswordNotProvidedException e) {
202 setStatusMessage("Build not executed: Password not provided for server");
203 } catch (RemoteApiException e) {
204 setStatusMessage("Build not executed: " + e.getMessage());
205 }
206
207 }
208 }, "atlassian-idea-plugin execute build").start();
209 }
210
211 public void runBuild() {
212 BambooBuildAdapterIdea build = table.getSelectedObject();
213 executeBuild(build);
214 }
215
216 private void setBuilds(Collection<BambooBuild> builds) {
217 boolean haveErrors = false;
218 List<BambooBuildAdapterIdea> buildAdapters = new ArrayList<BambooBuildAdapterIdea>();
219 Date lastPollingTime = null;
220 for (BambooBuild build : builds) {
221 if (!haveErrors) {
222 if (build.getStatus() == BuildStatus.UNKNOWN) {
223 setStatusMessage(build.getMessage(), true);
224 haveErrors = true;
225 }
226 }
227 if (build.getPollingTime() != null) {
228 lastPollingTime = build.getPollingTime();
229 }
230 buildAdapters.add(new BambooBuildAdapterIdea(build));
231 }
232
233
234 int selectedItem = table.getSelectedRow();
235
236 listTableModel.setItems(buildAdapters);
237 listTableModel.fireTableDataChanged();
238 table.setEnabled(true);
239 table.setForeground(UIUtil.getActiveTextColor());
240
241
242 table.getSelectionModel().setSelectionInterval(selectedItem, selectedItem);
243
244 if (!haveErrors) {
245 StringBuffer sb = new StringBuffer();
246 sb.append("Loaded <b>");
247 sb.append(builds.size());
248 sb.append("</b> builds");
249 if (lastPollingTime != null) {
250 sb.append(" at <b>");
251 sb.append(TIME_DF.print(lastPollingTime.getTime()));
252 sb.append("</b>");
253 }
254 sb.append(".");
255 setStatusMessage((sb.toString()));
256 }
257 }
258
259 @SuppressWarnings("unchecked")
260 public List<BambooBuildAdapterIdea> getBuilds() {
261 return listTableModel.getItems();
262 }
263
264 public void updateBuildStatuses(Collection<BambooBuild> buildStatuses) {
265 setBuilds(buildStatuses);
266 }
267
268 public void resetState() {
269 updateBuildStatuses(new ArrayList<BambooBuild>());
270 }
271
272 public boolean getExecuteBuildEnabled() {
273 BambooBuildAdapterIdea build = table.getSelectedObject();
274 return build != null && build.getEnabled();
275 }
276
277 private boolean getBamboo2ActionsEnabled() {
278 BambooBuildAdapterIdea build = table.getSelectedObject();
279 if (build != null) {
280 return build.isBamboo2() && build.getEnabled();
281 } else {
282 return false;
283 }
284 }
285
286 public boolean getLabelBuildEnabled() {
287 return getBamboo2ActionsEnabled();
288 }
289
290 public boolean getCommentBuildEnabled() {
291 return getBamboo2ActionsEnabled();
292 }
293
294 public void viewBuild() {
295 BambooBuildAdapterIdea build = table.getSelectedObject();
296 if (build != null) {
297 BrowserUtil.launchBrowser(build.getBuildResultUrl());
298 }
299 }
300
301 public boolean canShowFailedTests() {
302 BambooBuildAdapterIdea build = table.getSelectedObject();
303 if (build == null) {
304 return false;
305 }
306 return (build.isBamboo2() && (build.getTestsFailed() > 0));
307 }
308
309 public void showBuildStackTrace() {
310 final BambooBuildAdapterIdea build = table.getSelectedObject();
311
312 new Thread(new Runnable() {
313 public void run() {
314 setStatusMessage("Getting test results for build " + build.getBuildKey() + "...");
315 try {
316 BuildDetails details = bambooFacade.getBuildDetails(
317 build.getServer(), build.getBuildKey(), build.getBuildNumber());
318 final List<TestDetails> failedTests = details.getFailedTestDetails();
319 final List<TestDetails> succeededTests = details.getSuccessfulTestDetails();
320 SwingUtilities.invokeLater(new Runnable() {
321 public void run() {
322 testResultsToolWindow.showTestResults(
323 build.getBuildKey(), build.getBuildNumber(), failedTests, succeededTests);
324 }
325 });
326 setStatusMessage("Test results for build " + build.getBuildKey() + " received");
327 } catch (ServerPasswordNotProvidedException e) {
328 setStatusMessage("Failed to get test results: Password not provided for server");
329 } catch (RemoteApiException e) {
330 setStatusMessage("Failed to get test results: " + e.getMessage());
331 }
332
333 }
334 }, "atlassian-idea-plugin get stack traces").start();
335 }
336
337 public boolean canShowChanges() {
338 BambooBuildAdapterIdea build = table.getSelectedObject();
339 if (build == null) {
340 return false;
341 }
342 return build.isBamboo2();
343 }
344
345 public void showChanges() {
346 final BambooBuildAdapterIdea build = table.getSelectedObject();
347
348 new Thread(new Runnable() {
349 public void run() {
350 setStatusMessage("Getting changes for build " + build.getBuildKey() + "...");
351 try {
352 BuildDetails details = bambooFacade.getBuildDetails(
353 build.getServer(), build.getBuildKey(), build.getBuildNumber());
354 final List<BambooChangeSet> commits = details.getCommitInfo();
355 SwingUtilities.invokeLater(new Runnable() {
356 public void run() {
357 buildChangesToolWindow.showBuildChanges(
358 build.getBuildKey(), build.getBuildNumber(), commits);
359 }
360 });
361 setStatusMessage("Changes for build " + build.getBuildKey() + " received");
362 } catch (ServerPasswordNotProvidedException e) {
363 setStatusMessage("Failed to get changes: Password not provided for server");
364 } catch (RemoteApiException e) {
365 setStatusMessage("Failed to get changes: " + e.getMessage());
366 }
367
368 }
369 }, "atlassian-idea-plugin get changes").start();
370 }
371
372
373 public void showBuildLog() {
374 final BambooBuildAdapterIdea build = table.getSelectedObject();
375
376 new Thread(new Runnable() {
377 public void run() {
378 setStatusMessage("Getting build log: " + build.getBuildKey() + "...");
379 try {
380 final byte[] log = bambooFacade.getBuildLogs(
381 build.getServer(), build.getBuildKey(), build.getBuildNumber());
382 final String title = "Bamboo build: "
383 + build.getServer().getName() + ": "
384 + build.getBuildKey() + "-" + build.getBuildNumber();
385 SwingUtilities.invokeLater(new Runnable() {
386 public void run() {
387 PlainTextMemoryVirtualFile vf = new PlainTextMemoryVirtualFile(title, new String(log));
388 FileEditorManager.getInstance(project).openFile(vf, true);
389 }
390 });
391 setStatusMessage("Changes for build " + build.getBuildKey() + " received");
392 } catch (ServerPasswordNotProvidedException e) {
393 setStatusMessage("Failed to get changes: Password not provided for server");
394 } catch (RemoteApiException e) {
395 setStatusMessage("Failed to get changes: " + e.getMessage());
396 }
397
398 }
399 }, "atlassian-idea-plugin get changes").start();
400 }
401 }