001 /* 002 * SonarQube, open source software quality management tool. 003 * Copyright (C) 2008-2014 SonarSource 004 * mailto:contact AT sonarsource DOT com 005 * 006 * SonarQube is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * SonarQube is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020 package org.sonar.api.resources; 021 022 import com.google.common.collect.ImmutableList; 023 import com.google.common.collect.Lists; 024 import org.apache.commons.configuration.Configuration; 025 import org.apache.commons.lang.StringUtils; 026 import org.apache.commons.lang.builder.ToStringBuilder; 027 import org.apache.maven.project.MavenProject; 028 import org.sonar.api.CoreProperties; 029 import org.sonar.api.component.Component; 030 031 import javax.annotation.Nullable; 032 033 import java.util.ArrayList; 034 import java.util.Date; 035 import java.util.List; 036 037 /** 038 * A class that manipulates Projects in the Sonar way. 039 * 040 * @since 1.10 041 */ 042 public class Project extends Resource implements Component { 043 044 /** 045 * Internal use 046 */ 047 public static final Language NONE_LANGUAGE = new AbstractLanguage("none", "None") { 048 @Override 049 public String[] getFileSuffixes() { 050 return new String[0]; 051 } 052 }; 053 054 static final String MAVEN_KEY_FORMAT = "%s:%s"; 055 private static final String BRANCH_KEY_FORMAT = "%s:%s"; 056 057 public static final String SCOPE = Scopes.PROJECT; 058 059 /** 060 * @deprecated since version 1.11. Constant moved to CoreProperties 061 */ 062 @Deprecated 063 public static final String PARAM_REUSE_RULES_CONFIG = CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY; 064 065 /** 066 * Enumerates the type of possible analysis 067 * @deprecated since 4.4 Since 4.3 SQ will no more run tests. So basically it's always reuse report. 068 */ 069 @Deprecated 070 public enum AnalysisType { 071 STATIC, DYNAMIC, REUSE_REPORTS; 072 073 /** 074 * @param includeReuseReportMode whether to count report reuse as dynamic or not 075 * @return whether this a dynamic analysis 076 */ 077 public boolean isDynamic(boolean includeReuseReportMode) { 078 return equals(Project.AnalysisType.DYNAMIC) || 079 (equals(Project.AnalysisType.REUSE_REPORTS) && includeReuseReportMode); 080 } 081 } 082 083 private MavenProject pom; 084 private String branch; 085 private ProjectFileSystem fileSystem; 086 private Configuration configuration; 087 private String name; 088 private String description; 089 private String packaging; 090 private Language language; 091 private Date analysisDate; 092 private AnalysisType analysisType; 093 private String analysisVersion; 094 095 // modules tree 096 private Project parent; 097 private List<Project> modules = new ArrayList<Project>(); 098 099 public Project(String key) { 100 setKey(key); 101 setDeprecatedKey(key); 102 setEffectiveKey(key); 103 } 104 105 public Project(String key, String branch, String name) { 106 if (StringUtils.isNotBlank(branch)) { 107 setKey(String.format(BRANCH_KEY_FORMAT, key, branch)); 108 this.name = String.format("%s %s", name, branch); 109 } else { 110 setKey(key); 111 this.name = name; 112 } 113 setDeprecatedKey(getKey()); 114 setEffectiveKey(getKey()); 115 this.branch = branch; 116 } 117 118 public String getBranch() { 119 return branch; 120 } 121 122 /** 123 * For internal use only. 124 */ 125 public Project setBranch(String branch) { 126 this.branch = branch; 127 return this; 128 } 129 130 /** 131 * For internal use only. 132 */ 133 public final Project setPom(MavenProject pom) { 134 this.pom = pom; 135 return this; 136 } 137 138 /** 139 * @return the project's packaging 140 * @deprecated in 2.8. See http://jira.codehaus.org/browse/SONAR-2341 141 */ 142 @Deprecated 143 public String getPackaging() { 144 return packaging; 145 } 146 147 @Override 148 public String getName() { 149 return name; 150 } 151 152 @Override 153 public String getLongName() { 154 return name; 155 } 156 157 @Override 158 public String getDescription() { 159 return description; 160 } 161 162 /** 163 * For internal use only. 164 */ 165 public Project setName(String name) { 166 this.name = name; 167 return this; 168 } 169 170 /** 171 * For internal use only. 172 */ 173 public Project setDescription(String description) { 174 this.description = description; 175 return this; 176 } 177 178 /** 179 * For internal use only. 180 * 181 * @deprecated in 2.8. See http://jira.codehaus.org/browse/SONAR-2341 182 */ 183 @Deprecated 184 public Project setPackaging(String packaging) { 185 this.packaging = packaging; 186 return this; 187 } 188 189 /** 190 * @return whether the current project is root project 191 */ 192 public boolean isRoot() { 193 return getParent() == null; 194 } 195 196 public Project getRoot() { 197 return parent == null ? this : parent.getRoot(); 198 } 199 200 /** 201 * @return whether the current project is a module 202 */ 203 public boolean isModule() { 204 return !isRoot(); 205 } 206 207 /** 208 * @deprecated since 4.4 Since 4.3 SQ will no more run tests. So basically it's always reuse report. 209 */ 210 @Deprecated 211 public AnalysisType getAnalysisType() { 212 return analysisType; 213 } 214 215 /** 216 * @deprecated since 4.4 Since 4.3 SQ will no more run tests. So basically it's always reuse report. 217 */ 218 @Deprecated 219 public Project setAnalysisType(AnalysisType at) { 220 this.analysisType = at; 221 return this; 222 } 223 224 /** 225 * whether it's the latest analysis done on this project (displayed in sonar dashboard) or an analysis on a past revision. 226 * 227 * @since 2.0 228 * @deprecated in 3.6. The analysis is now always the latest one (past analysis must be done in a chronological order). See http://jira.codehaus.org/browse/SONAR-4334 229 */ 230 @Deprecated 231 public boolean isLatestAnalysis() { 232 return true; 233 } 234 235 /** 236 * For internal use only. 237 * 238 * @deprecated in 3.6. It's not possible to analyze a project before the latest known quality snapshot. 239 * See http://jira.codehaus.org/browse/SONAR-4334 240 */ 241 @Deprecated 242 public Project setLatestAnalysis(boolean b) { 243 if (!b) { 244 throw new UnsupportedOperationException("The analysis is always the latest one. " + 245 "Past analysis must be done in a chronological order."); 246 } 247 return this; 248 } 249 250 /** 251 * @return the project language when there is only one language 252 * @deprecated since 4.2 use {@link org.sonar.api.batch.fs.FileSystem#languages()} 253 */ 254 @Deprecated 255 @Override 256 public Language getLanguage() { 257 return language; 258 } 259 260 /** 261 * Internal use 262 */ 263 public Project setLanguage(Language language) { 264 this.language = language; 265 return this; 266 } 267 268 /** 269 * @return the language key or empty if no language is specified 270 * @deprecated since 4.2 use {@link org.sonar.api.batch.fs.FileSystem#languages()} 271 */ 272 @Deprecated 273 public String getLanguageKey() { 274 return configuration.getString(CoreProperties.PROJECT_LANGUAGE_PROPERTY, ""); 275 } 276 277 /** 278 * For internal use only. 279 */ 280 public Project setAnalysisDate(Date analysisDate) { 281 this.analysisDate = analysisDate; 282 return this; 283 } 284 285 /** 286 * For internal use only. 287 */ 288 public Project setAnalysisVersion(String analysisVersion) { 289 this.analysisVersion = analysisVersion; 290 return this; 291 } 292 293 /** 294 * @return the scope of the current object 295 */ 296 @Override 297 public String getScope() { 298 return Scopes.PROJECT; 299 } 300 301 /** 302 * @return the qualifier of the current object 303 */ 304 @Override 305 public String getQualifier() { 306 return isRoot() ? Qualifiers.PROJECT : Qualifiers.MODULE; 307 } 308 309 @Override 310 public boolean matchFilePattern(String antPattern) { 311 return false; 312 } 313 314 @Override 315 public Project getParent() { 316 return parent; 317 } 318 319 /** 320 * For internal use only. 321 */ 322 public Project setParent(Project parent) { 323 this.parent = parent; 324 if (parent != null) { 325 parent.modules.add(this); 326 } 327 return this; 328 } 329 330 /** 331 * For internal use only. 332 */ 333 public void removeFromParent() { 334 if (parent != null) { 335 parent.modules.remove(this); 336 } 337 } 338 339 /** 340 * @return the list of modules 341 */ 342 public List<Project> getModules() { 343 return modules; 344 } 345 346 /** 347 * @return whether to use external source for rules configuration 348 * @deprecated since 2.5. See discussion from http://jira.codehaus.org/browse/SONAR-1873 349 */ 350 @Deprecated 351 public boolean getReuseExistingRulesConfig() { 352 return configuration != null && configuration.getBoolean(CoreProperties.REUSE_RULES_CONFIGURATION_PROPERTY, false); 353 } 354 355 /** 356 * @return the current version of the project 357 */ 358 public String getAnalysisVersion() { 359 return analysisVersion; 360 } 361 362 /** 363 * @return the analysis date, i.e. the date that will be used to store the snapshot 364 */ 365 public Date getAnalysisDate() { 366 return analysisDate; 367 } 368 369 /** 370 * Patterns of resource exclusion as defined in project settings page. 371 * 372 * @since 3.3 also applies exclusions in general settings page and global exclusions. 373 * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5 374 */ 375 @Deprecated 376 public String[] getExclusionPatterns() { 377 return trimExclusions(ImmutableList.<String>builder() 378 .add(configuration.getStringArray(CoreProperties.PROJECT_EXCLUSIONS_PROPERTY)) 379 .add(configuration.getStringArray(CoreProperties.GLOBAL_EXCLUSIONS_PROPERTY)).build()); 380 } 381 382 /** 383 * Patterns of test exclusion as defined in project settings page. 384 * Also applies exclusions in general settings page and global exclusions. 385 * 386 * @since 3.3 387 * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5 388 */ 389 @Deprecated 390 public String[] getTestExclusionPatterns() { 391 return trimExclusions(ImmutableList.<String>builder() 392 .add(configuration.getStringArray(CoreProperties.PROJECT_TEST_EXCLUSIONS_PROPERTY)) 393 .add(configuration.getStringArray(CoreProperties.GLOBAL_TEST_EXCLUSIONS_PROPERTY)).build()); 394 } 395 396 // http://jira.codehaus.org/browse/SONAR-2261 - exclusion must be trimmed 397 private static String[] trimExclusions(List<String> exclusions) { 398 List<String> trimmed = Lists.newArrayList(); 399 for (String exclusion : exclusions) { 400 trimmed.add(StringUtils.trim(exclusion)); 401 } 402 return trimmed.toArray(new String[trimmed.size()]); 403 } 404 405 /** 406 * Set exclusion patterns. Configuration is not saved, so this method must be used ONLY IN UNIT TESTS. 407 * @deprecated replaced by {@link org.sonar.api.scan.filesystem.FileExclusions} in version 3.5 408 */ 409 @Deprecated 410 public Project setExclusionPatterns(String[] s) { 411 throw new UnsupportedOperationException("deprecated in 3.5"); 412 } 413 414 /** 415 * Note: it's better to get a reference on ProjectFileSystem as an IoC dependency (constructor parameter) 416 * @deprecated replaced by {@link org.sonar.api.scan.filesystem.ModuleFileSystem} in 3.5 417 */ 418 @Deprecated 419 public ProjectFileSystem getFileSystem() { 420 return fileSystem; 421 } 422 423 /** 424 * For internal use only. 425 * 426 * @deprecated since 2.6. See http://jira.codehaus.org/browse/SONAR-2126 427 */ 428 @Deprecated 429 public Project setFileSystem(ProjectFileSystem fs) { 430 this.fileSystem = fs; 431 return this; 432 } 433 434 /** 435 * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011 436 */ 437 @Deprecated 438 public String getGroupId() { 439 return pom.getGroupId(); 440 } 441 442 /** 443 * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011 444 */ 445 @Deprecated 446 public String getArtifactId() { 447 return pom.getArtifactId(); 448 } 449 450 /** 451 * @return the underlying Maven project 452 * @deprecated since 2.5. See http://jira.codehaus.org/browse/SONAR-2011 , 453 * MavenProject can be retrieved as an IoC dependency 454 */ 455 @Deprecated 456 public MavenProject getPom() { 457 return pom; 458 } 459 460 /** 461 * @return the project configuration 462 * @deprecated since 2.12. The component org.sonar.api.config.Settings must be used. 463 */ 464 @Deprecated 465 public Configuration getConfiguration() { 466 return configuration; 467 } 468 469 /** 470 * For internal use only. 471 */ 472 public final Project setConfiguration(Configuration configuration) { 473 this.configuration = configuration; 474 return this; 475 } 476 477 /** 478 * @deprecated since 3.6. Replaced by {@link org.sonar.api.config.Settings}. 479 */ 480 @Deprecated 481 public Object getProperty(String key) { 482 return configuration != null ? configuration.getProperty(key) : null; 483 } 484 485 public static Project createFromMavenIds(String groupId, String artifactId) { 486 return createFromMavenIds(groupId, artifactId, null); 487 } 488 489 public static Project createFromMavenIds(String groupId, String artifactId, @Nullable String branch) { 490 return new Project(String.format(MAVEN_KEY_FORMAT, groupId, artifactId), branch, ""); 491 } 492 493 @Override 494 public String toString() { 495 return new ToStringBuilder(this) 496 .append("id", getId()) 497 .append("key", getKey()) 498 .append("qualifier", getQualifier()) 499 .toString(); 500 } 501 502 @Override 503 public String key() { 504 return getKey(); 505 } 506 507 @Override 508 public String name() { 509 return getName(); 510 } 511 512 @Override 513 public String path() { 514 return getPath(); 515 } 516 517 @Override 518 public String longName() { 519 return getLongName(); 520 } 521 522 @Override 523 public String qualifier() { 524 return getQualifier(); 525 } 526 }