PageRenderTime 53ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/LoadSampleData.groovy

https://bitbucket.org/nmuldoon/greenhopper-sample-data
Groovy | 438 lines | 346 code | 58 blank | 34 comment | 82 complexity | df460855035196beba784cbd3ad1369b MD5 | raw file
  1. import com.atlassian.jira.ComponentManager
  2. import com.atlassian.plugin.PluginAccessor
  3. import org.springframework.beans.factory.support.*
  4. import com.atlassian.plugin.osgi.container.OsgiContainerManager
  5. import org.springframework.context.ApplicationContext
  6. import org.osgi.framework.Constants
  7. import com.atlassian.jira.project.ProjectManager
  8. import com.atlassian.jira.bc.project.ProjectService
  9. import com.atlassian.jira.bc.project.ProjectService.DeleteProjectValidationResult
  10. import com.atlassian.jira.util.SimpleErrorCollection
  11. import org.joda.time.DateTime
  12. import org.joda.time.Period
  13. import org.codehaus.jackson.JsonParser
  14. import org.codehaus.jackson.JsonFactory
  15. import org.codehaus.jackson.node.ObjectNode
  16. import org.codehaus.jackson.JsonParser.Feature
  17. import org.codehaus.jackson.map.ObjectMapper
  18. import org.apache.commons.httpclient.HttpClient;
  19. import org.apache.commons.httpclient.methods.GetMethod;
  20. def componentManager = ComponentManager.getInstance()
  21. def jiraAuthenticationContext = componentManager.getJiraAuthenticationContext()
  22. def issueManager = componentManager.getIssueManager()
  23. def customFieldManager = componentManager.getCustomFieldManager();
  24. def constantsManager = componentManager.getConstantsManager();
  25. def user = jiraAuthenticationContext.getUser()
  26. /*
  27. * Import options section. Most of these can be overriden with entries in the ghsample -> options
  28. * object of the JSON
  29. */
  30. // Project key to be be put as ${projectKey} in the Velocity template handed to JIM for import
  31. //
  32. // If the JSON already includes a project key and name, those will NOT be overridden
  33. def projectKey = "SCT";
  34. def projectName = "Scrum Sample";
  35. // Delete the projectKey project if it exists
  36. def deleteProjectIfExists = 1;
  37. // Delete any sprints attached to the issues in an existing project being deleted
  38. def deleteIssueSprintsIfProjectExists = 1;
  39. // File to import
  40. def url = "https://bitbucket.org/nmuldoon/greenhopper-sample-data/raw/master/pomodoroall.json"
  41. OsgiContainerManager osgiContainerManager = ComponentManager.getComponentInstanceOfType(OsgiContainerManager.class);
  42. ProjectService projectService = ComponentManager.getComponent(ProjectService.class);
  43. ProjectManager projectManager = componentManager.getProjectManager();
  44. def greenhopperContext = GetApplicationContext("com.pyxis.greenhopper.jira");
  45. if (!greenhopperContext)
  46. {
  47. println "Could not find GreenHopper";
  48. return "NoGreenHopper";
  49. }
  50. def sprintManager = greenhopperContext.getBean("sprintManagerImpl");
  51. PluginAccessor pluginAccessor = componentManager.getPluginAccessor();
  52. Class sampleDataImporterClass = pluginAccessor.getClassLoader().findClass("com.atlassian.jira.plugins.importer.sample.SampleDataImporter");
  53. if (!sampleDataImporterClass)
  54. {
  55. println "Could not find importer";
  56. return "No JIM";
  57. }
  58. def sampleDataImporter = componentManager.getOSGiComponentInstanceOfType(sampleDataImporterClass);
  59. if (!sampleDataImporter)
  60. {
  61. println "Could not find importer";
  62. return "No Sample Importer";
  63. }
  64. println "Got importer";
  65. // Grab the JSON file when requested
  66. def getResponseText(url) {
  67. def get = new GetMethod(url)
  68. new HttpClient().executeMethod(get)
  69. BufferedInputStream bis = new BufferedInputStream(get.getResponseBodyAsStream())
  70. return bis.getText('UTF-8')
  71. }
  72. // Read the JSON input file
  73. def json
  74. try {
  75. json = getResponseText(url);
  76. } catch (FileNotFoundException) {
  77. println "File "+url+" not found";
  78. return "No " + url;
  79. }
  80. println "Got JSON";
  81. // Parse the JSON (stripping the comments in the process)
  82. ObjectMapper mapper = new ObjectMapper();
  83. mapper.configure(JsonParser.Feature.ALLOW_COMMENTS, true);
  84. def jsonNode = mapper.readTree(json);
  85. println "Parsed JSON";
  86. // Initialize our velocity template variables
  87. Map velocityMap = new HashMap();
  88. // Work out which project we will be importing to
  89. def jsonProjectKey = jsonNode.path("projects").path(0).path("key").getTextValue();
  90. if (jsonProjectKey != null && !jsonProjectKey.equals('${projectKey}'))
  91. {
  92. println "Project key is included in the JSON, key is " + jsonProjectKey;
  93. projectKey = jsonProjectKey;
  94. }
  95. def jsonProjectName = jsonNode.path("projects").path(0).path("name").getTextValue();
  96. if (jsonProjectName != null && !jsonProjectName.equals('${projectName}'))
  97. {
  98. println "Project name is included in the JSON, name is " + jsonProjectName;
  99. projectName = jsonProjectName;
  100. }
  101. // Get the currenttime that we will use for Sprint creation. We actually add
  102. // 30 seconds to everything so that the Sprint objects show the Sprint started
  103. // AFTER the issues joined the Sprint
  104. def currentTime = DateTime.now().plusSeconds(30);
  105. // Parse the GreenHopper metadata information from the JSON if it's there
  106. def ghsampleNode = jsonNode.get("ghsample");
  107. if (ghsampleNode != null)
  108. {
  109. println "Parsing GreenHopper Sample Data information block";
  110. // Read the options
  111. def optionsNode = ghsampleNode.get("options");
  112. if (optionsNode != null && optionsNode.isObject())
  113. {
  114. def valueNode = optionsNode.get("deleteProjectIfExists");
  115. if (valueNode != null)
  116. {
  117. deleteProjectIfExists = valueNode.getIntValue();
  118. println "Option deleteProjectIfExists set to " + deleteProjectIfExists;
  119. }
  120. valueNode = optionsNode.get("deleteIssueSprintsIfProjectExists");
  121. if (valueNode != null)
  122. {
  123. deleteIssueSprintsIfProjectExists = valueNode.getIntValue();
  124. println "Option deleteIssueSprintsIfProjectExists set to " + deleteIssueSprintsIfProjectExists;
  125. }
  126. }
  127. // Get the status ids we need to put in to the velocity template
  128. def statusesNode = ghsampleNode.get("statuses");
  129. if (statusesNode != null)
  130. {
  131. println "Parsing statuses";
  132. for (statusVar in statusesNode.getFieldNames())
  133. {
  134. def statusName = statusesNode.get(statusVar);
  135. statusVar = statusVar.replaceFirst('^\\$\\{(.*)\\}$', '$1');
  136. println " " + statusVar + " = " + statusName;
  137. def status = constantsManager.getStatusByName(statusName.getValueAsText());
  138. if (!status)
  139. {
  140. println "Error: Could not find status " + statusName;
  141. return "No Status " + statusName;
  142. }
  143. else
  144. {
  145. println " " + statusVar + " = " + status.getId();
  146. velocityMap.put(statusVar, status.getId());
  147. }
  148. }
  149. }
  150. // Get the field ids we need to put in to the velocity template
  151. def fieldsNode = ghsampleNode.get("fields");
  152. if (fieldsNode != null)
  153. {
  154. println "Parsing fields";
  155. for (fieldVar in fieldsNode.getFieldNames())
  156. {
  157. def fieldName = fieldsNode.get(fieldVar);
  158. fieldVar = fieldVar.replaceFirst('^\\$\\{(.*)\\}$', '$1');
  159. println " " + fieldVar + " = " + fieldName;
  160. // We shouldn't just get any field by name here, if it's a GreenHopper
  161. // field we need to be sure to get only the GreenHopper one (e.g.
  162. // only the GreenHopper Story Points/Business Value/Sprint fields)
  163. def field = customFieldManager.getCustomFieldObjectByName(fieldName.getValueAsText());
  164. if (!field)
  165. {
  166. println "Error: Could not find field " + fieldName;
  167. return "No field " + fieldName;
  168. }
  169. else
  170. {
  171. println " " + fieldVar + " = " + field.getId();
  172. velocityMap.put(fieldVar, field.getId());
  173. }
  174. }
  175. }
  176. // Create the sprints we need
  177. def sprintsNode = ghsampleNode.get("sprints");
  178. if (sprintsNode != null)
  179. {
  180. def sprintClass = greenhopperContext.getClassLoader().findClass("com.atlassian.greenhopper.service.sprint.Sprint");
  181. println "Parsing sprints";
  182. for (sprintVar in sprintsNode.getFieldNames())
  183. {
  184. def sprintDef = sprintsNode.get(sprintVar);
  185. def sprintBuilder = sprintClass.getDeclaredMethod("builder").invoke(null, null)
  186. def startDate = currentTime.plus(Period.parse(sprintDef.get("started").getTextValue()));
  187. def endDate = currentTime.plus(Period.parse(sprintDef.get("ends").getTextValue()));
  188. def completedDate;
  189. if (sprintDef.get("completed") != null)
  190. completedDate = currentTime.plus(Period.parse(sprintDef.get("completed").getTextValue()));
  191. def sprintName = sprintDef.get("name").getTextValue();
  192. sprintBuilder.name(sprintName).startDate(startDate).endDate(endDate);
  193. if (completedDate != null)
  194. sprintBuilder.completeDate(completedDate).state(sprintBuilder.state.CLOSE);
  195. else
  196. sprintBuilder.state(sprintBuilder.state.ACTIVE);
  197. def sprint = sprintBuilder.build();
  198. print "Building sprint " + sprint;
  199. def outcome = sprintManager.createSprint(sprint);
  200. if (!outcome.isValid())
  201. {
  202. println "Couldn't create Sprint";
  203. return "Failed Creating Sprint";
  204. }
  205. println "Sprint '" + sprintName + "' created with ID " + outcome.getValue().getId();
  206. sprintVar = sprintVar.replaceFirst('^\\$\\{(.*)\\}$', '$1');
  207. println " " + sprintVar + " = " + outcome.getValue().getId();
  208. velocityMap.put(sprintVar, outcome.getValue().getId());
  209. }
  210. }
  211. ((ObjectNode) jsonNode).remove("ghsample");
  212. println "Removed ghsample node";
  213. }
  214. def projectResult = projectService.getProjectByKey(user, projectKey);
  215. def existingProject;
  216. if (!projectResult.isValid())
  217. {
  218. println "Did not find existing project with key " + projectKey;
  219. // return;
  220. }
  221. else
  222. {
  223. existingProject = projectResult.getProject();
  224. println "Found existing project with key " + projectKey;
  225. }
  226. // Look for the project by name too, if there is a different project we're broken
  227. def projectByName = projectManager.getProjectObjByName(projectName);
  228. if (projectByName)
  229. {
  230. println "Found existing project with name " + projectName;
  231. if (existingProject != null && projectByName.getId() != existingProject.getId())
  232. {
  233. println "Found two different existing projects matching project to import, one with key " + projectKey + ", one with name " + projectName + ", not sure what you want JIM/us to do\n";
  234. return "Two Projects";
  235. }
  236. else if (existingProject == null)
  237. {
  238. println "Did not find project by key but did find by name, not sure if you really want me to use/delete it";
  239. return "Project by name";
  240. }
  241. }
  242. if (deleteProjectIfExists && existingProject)
  243. {
  244. println "Got existing project by key, now deleting it";
  245. if (deleteIssueSprintsIfProjectExists)
  246. {
  247. def deleteSprints = [:];
  248. def sprintField = customFieldManager.getCustomFieldObjectByName("Sprint");
  249. for (issueId in componentManager.getIssueManager().getIssueIdsForProject(existingProject.getId()))
  250. {
  251. def issue = issueManager.getIssueObject(issueId);
  252. def sprintFieldVal = issue.getCustomFieldValue(sprintField);
  253. if (sprintFieldVal)
  254. {
  255. for (sprintObj in sprintFieldVal)
  256. {
  257. println "For issue " + issue.getKey() + " got sprint " + sprintObj.getId();
  258. if (!deleteSprints.get(sprintObj.getId()))
  259. deleteSprints[sprintObj.getId()] = sprintObj.getId();
  260. }
  261. }
  262. }
  263. for (sprint in deleteSprints)
  264. {
  265. println "Deleting sprint " + sprint.value;
  266. def sprintOutcome = sprintManager.getSprint(sprint.value);
  267. if (sprintOutcome.isValid())
  268. {
  269. sprintManager.deleteSprint(sprintOutcome.getValue());
  270. println "... done";
  271. }
  272. }
  273. }
  274. errorCollection = new SimpleErrorCollection();
  275. ProjectService.DeleteProjectValidationResult deleteResult = new ProjectService.DeleteProjectValidationResult(errorCollection, existingProject)
  276. projectService.deleteProject(user, deleteResult)
  277. if (!deleteResult.isValid())
  278. {
  279. println "Failed deleting project";
  280. return "Failed Deleting Project";
  281. }
  282. println "Deleted project"
  283. }
  284. velocityMap.put("loreum", "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.");
  285. velocityMap.put("projectKey", projectKey);
  286. velocityMap.put("projectName", projectName);
  287. velocityMap.put("currentUser", user.getName());
  288. // Regenerate the JSON
  289. StringWriter sw = new StringWriter();
  290. def jsonWriter = mapper.getJsonFactory().createJsonGenerator(sw);
  291. jsonWriter.useDefaultPrettyPrinter();
  292. jsonWriter.writeTree(jsonNode);
  293. json = sw.toString();
  294. // println json;
  295. // Call JIM to create the sample data
  296. SimpleErrorCollection errorCollection = new SimpleErrorCollection();
  297. def found = 0;
  298. for (method in sampleDataImporter.respondsTo("createSampleData"))
  299. {
  300. if (method.getParamsCount() < 1 || !method.getNativeParameterTypes()[0].equals(String))
  301. continue;
  302. if (method.getParamsCount() == 5 && method.getNativeParameterTypes()[0].equals(String))
  303. {
  304. sampleDataImporter.createSampleData(json, velocityMap, null, null, errorCollection);
  305. found = 1;
  306. break;
  307. }
  308. else if (method.getParamsCount() == 6)
  309. {
  310. sampleDataImporter.createSampleData(json, velocityMap, null, null, null, errorCollection);
  311. found = 1;
  312. break;
  313. }
  314. }
  315. if (!found)
  316. {
  317. println "Found no method to create sample data";
  318. return "NoMethod";
  319. }
  320. if (errorCollection.hasAnyErrors())
  321. {
  322. println "Import failed";
  323. for (error in errorCollection.getErrorMessages())
  324. println " " + error;
  325. return "Import Failed";
  326. }
  327. // Go through the new project issue by issue and check the Rank field,
  328. // which will cause the rank to be correctly populated in order of issuekey
  329. def project = componentManager.getProjectManager().getProjectObjByKey(projectKey);
  330. if (project)
  331. {
  332. def issueKeys = [];
  333. for (issueId in componentManager.getIssueManager().getIssueIdsForProject(project.getId()))
  334. {
  335. def issue = issueManager.getIssueObject(issueId);
  336. println " Got issue " + issue.getKey();
  337. issueKeys.push(issue.getKey());
  338. }
  339. println issueKeys + " " + issueKeys.getClass().getName();
  340. println Collections.sort(issueKeys);
  341. for (issueKey in issueKeys.sort { a,b -> if (a.length() != b.length()) a.length() - b.length() else a.compareTo(b) })
  342. {
  343. def issue = issueManager.getIssueObject(issueKey);
  344. println "Issue " + issueKey + " has rank " + issue.getCustomFieldValue(customFieldManager.getCustomFieldObjectByName("Rank"));
  345. }
  346. }
  347. // Delete any "External Issue ID" field created by JIM
  348. for (customField in customFieldManager.getCustomFieldObjectsByName("External issue ID"))
  349. {
  350. def associatedProjects = customField.getAssociatedProjects();
  351. if (associatedProjects.size() == 1 && associatedProjects.get(0).getString("key") == projectKey)
  352. {
  353. println "Deleting External issue ID field";
  354. customFieldManager.removeCustomField(customField);
  355. }
  356. }
  357. println "Import completed"
  358. return "Import Completed";
  359. def GetApplicationContext(app)
  360. {
  361. OsgiContainerManager osgiContainerManager = ComponentManager.getComponentInstanceOfType(OsgiContainerManager.class);
  362. def appContext;
  363. osgiContainerManager.getBundles()
  364. for (bundle in osgiContainerManager.getBundles())
  365. {
  366. def bundleContext = bundle.getBundleContext()
  367. if (bundle.getSymbolicName() != app)
  368. continue;
  369. for (service in bundleContext.getServiceReferences(ApplicationContext.class.getName(), null))
  370. {
  371. if (service.getProperty("org.springframework.context.service.name") == app)
  372. {
  373. appContext = bundleContext.getService(service)
  374. break;
  375. }
  376. }
  377. break;
  378. }
  379. return appContext;
  380. }