summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/AlertsEmailTemplate.java2
-rw-r--r--pom.xml4
-rw-r--r--server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java26
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/batch/GlobalAction.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java22
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/DefaultComponentFinder.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/AppAction.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/EventsWs.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java55
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/DbIdsRepository.java (renamed from server/sonar-server/src/main/java/org/sonar/server/computation/component/DbComponentsRefCache.java)56
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java6
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolder.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java32
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/ApplyPermissionsStep.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexComponentsStep.java17
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexTestsStep.java13
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsAndSnapshotsStep.java346
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java260
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java152
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java126
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java144
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java77
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java80
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java106
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java28
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PopulateComponentsUuidAndKeyStep.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeDatastoresStep.java20
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java16
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/dashboard/template/ProjectTimeMachineDashboard.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/migrations/MigrationStepModule.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/ReplaceIssueFiltersProjectKeyByUuid.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/AddNewCharacteristics.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleans.java43
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/debt/DebtCharacteristicsXMLImporter.java16
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelXMLExporter.java38
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java24
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsJsonWriter.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/es/request/ProxySearchRequestBuilder.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java30
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java24
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanService.java18
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanWs.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java28
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java20
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/measure/ws/ManualMeasuresWs.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricsWs.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java14
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/permission/PermissionFinder.java20
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/permission/PermissionQueryParser.java11
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWs.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/project/ws/DeleteAction.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QGatesWs.java1
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java12
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java8
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java28
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java29
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java4
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java16
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectsAction.java20
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinitionLoader.java16
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java15
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/RuleOperations.java9
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java25
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java35
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/source/db/FileSourceDao.java3
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/startup/JdbcDriverDeployer.java10
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/startup/LogServerId.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipFinder.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipService.java5
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexer.java7
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ws/FavoritesWs.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java33
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/user/ws/UserPropertiesWs.java2
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java27
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java52
-rw-r--r--server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java7
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImplTest.java (renamed from server/sonar-server/src/test/java/org/sonar/server/computation/component/DbComponentsRefCacheTest.java)29
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/batch/ComponentTreeRule.java127
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java25
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentImplTest.java5
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/component/DbIdsRepositoryTest.java62
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/component/TreeRootHolderImplTest.java45
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java22
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java27
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java22
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexTestsStepTest.java20
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsAndSnapshotsStepTest.java (renamed from server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java)287
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java109
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java32
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java34
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java86
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java21
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistProjectLinksStepTest.java72
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistTestsStepTest.java21
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java17
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java15
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/db/migrations/MigrationStepModuleTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest.java53
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java12
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java2
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java12
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java14
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java15
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java15
-rw-r--r--server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java33
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate-result.xml7
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate.xml7
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/schema.sql7
-rw-r--r--server/sonar-server/src/test/resources/org/sonar/server/metric/persistence/MetricDaoTest/manual_metric.xml4
-rw-r--r--server/sonar-web/Gruntfile.coffee8
-rw-r--r--server/sonar-web/pom.xml9
-rw-r--r--server/sonar-web/src/main/js/apps/groups/app.js47
-rw-r--r--server/sonar-web/src/main/js/apps/groups/create-view.js30
-rw-r--r--server/sonar-web/src/main/js/apps/groups/delete-view.js32
-rw-r--r--server/sonar-web/src/main/js/apps/groups/form-view.js25
-rw-r--r--server/sonar-web/src/main/js/apps/groups/group.js35
-rw-r--r--server/sonar-web/src/main/js/apps/groups/groups.js40
-rw-r--r--server/sonar-web/src/main/js/apps/groups/header-view.js25
-rw-r--r--server/sonar-web/src/main/js/apps/groups/layout.js16
-rw-r--r--server/sonar-web/src/main/js/apps/groups/list-footer-view.js34
-rw-r--r--server/sonar-web/src/main/js/apps/groups/list-item-view.js59
-rw-r--r--server/sonar-web/src/main/js/apps/groups/list-view.js11
-rw-r--r--server/sonar-web/src/main/js/apps/groups/search-view.js49
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-delete.hbs13
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-form.hbs24
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-header.hbs9
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-layout.hbs6
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-list-footer.hbs6
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-list-item.hbs16
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs6
-rw-r--r--server/sonar-web/src/main/js/apps/groups/templates/groups-users.hbs10
-rw-r--r--server/sonar-web/src/main/js/apps/groups/update-view.js29
-rw-r--r--server/sonar-web/src/main/js/apps/groups/users-view.js42
-rw-r--r--server/sonar-web/src/main/js/apps/issues/templates/issues-issue-filter.hbs8
-rw-r--r--server/sonar-web/src/main/js/apps/provisioning/delete-view.js4
-rw-r--r--server/sonar-web/src/main/js/apps/provisioning/form-view.js8
-rw-r--r--server/sonar-web/src/main/js/apps/provisioning/list-footer-view.js2
-rw-r--r--server/sonar-web/src/main/js/apps/provisioning/projects.js2
-rw-r--r--server/sonar-web/src/main/js/apps/users/change-password-view.js4
-rw-r--r--server/sonar-web/src/main/js/apps/users/deactivate-view.js4
-rw-r--r--server/sonar-web/src/main/js/apps/users/form-view.js10
-rw-r--r--server/sonar-web/src/main/js/apps/users/groups-view.js20
-rw-r--r--server/sonar-web/src/main/js/apps/users/list-footer-view.js2
-rw-r--r--server/sonar-web/src/main/js/apps/users/list-item-view.js2
-rw-r--r--server/sonar-web/src/main/js/apps/users/users.js2
-rw-r--r--server/sonar-web/src/main/js/components/common/select-list.js8
-rw-r--r--server/sonar-web/src/main/js/components/issue/issue-view.js10
-rw-r--r--server/sonar-web/src/main/js/components/issue/manual-issue-view.js66
-rw-r--r--server/sonar-web/src/main/js/components/issue/models/issue.js34
-rw-r--r--server/sonar-web/src/main/js/components/issue/templates/issue.hbs117
-rw-r--r--server/sonar-web/src/main/js/components/issue/templates/manual-issue.hbs42
-rw-r--r--server/sonar-web/src/main/js/components/issue/views/comment-form-view.js20
-rw-r--r--server/sonar-web/src/main/js/components/issue/views/transitions-form-view.js1
-rw-r--r--server/sonar-web/src/main/js/components/source-viewer/main.js4
-rw-r--r--server/sonar-web/src/main/js/libs/third-party/backbone-super.js111
-rw-r--r--server/sonar-web/src/main/less/components/issues.less19
-rw-r--r--server/sonar-web/src/main/less/components/panels.less2
-rw-r--r--server/sonar-web/src/main/less/init/forms.less28
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/controllers/groups_controller.rb168
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb8
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_create_form.html.erb34
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_edit_form.html.erb34
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_select_user.html.erb36
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb71
-rw-r--r--server/sonar-web/src/main/webapp/WEB-INF/db/migrate/916_feed_metrics_booleans.rb31
-rw-r--r--server/sonar-web/src/test/js/groups-spec.js355
-rw-r--r--server/sonar-web/src/test/json/groups-spec/error.json7
-rw-r--r--server/sonar-web/src/test/json/groups-spec/search-big-1.json13
-rw-r--r--server/sonar-web/src/test/json/groups-spec/search-big-2.json13
-rw-r--r--server/sonar-web/src/test/json/groups-spec/search-created.json25
-rw-r--r--server/sonar-web/src/test/json/groups-spec/search-filtered.json13
-rw-r--r--server/sonar-web/src/test/json/groups-spec/search-updated.json19
-rw-r--r--server/sonar-web/src/test/json/groups-spec/search.json19
-rw-r--r--server/sonar-web/src/test/json/groups-spec/users.json17
-rw-r--r--server/sonar-web/src/test/views/groups.jade5
-rw-r--r--server/sonar-web/src/test/views/layouts/main.jade1
-rw-r--r--sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java10
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java5
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/compute/AbstractNewCoverageFileAnalyzer.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/compute/CountUnresolvedIssuesDecorator.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/compute/TimeMachineConfigurationPersister.java2
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/debt/DebtDecorator.java16
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java30
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java12
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingDecorator.java14
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java7
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java5
-rw-r--r--sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java9
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/Module.java9
-rw-r--r--sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java34
-rw-r--r--sonar-core/src/main/java/org/sonar/core/metric/db/MetricDto.java30
-rw-r--r--sonar-core/src/main/java/org/sonar/core/notification/DefaultNotificationManager.java14
-rw-r--r--sonar-core/src/main/java/org/sonar/core/permission/PermissionQuery.java8
-rw-r--r--sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java2
-rw-r--r--sonar-core/src/main/java/org/sonar/core/resource/ResourceKeyUpdaterDao.java13
-rw-r--r--sonar-core/src/main/java/org/sonar/core/timemachine/Periods.java26
-rw-r--r--sonar-core/src/main/java/org/sonar/core/user/GroupMembershipQuery.java2
-rw-r--r--sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql1
-rw-r--r--sonar-core/src/test/java/org/sonar/core/component/ModuleTest.java80
-rw-r--r--sonar-core/src/test/java/org/sonar/core/component/SnapshotDtoTest.java1
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java8
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java5
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/rules/Rule.java30
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleParamType.java5
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java46
-rw-r--r--sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java12
232 files changed, 3876 insertions, 2366 deletions
diff --git a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/AlertsEmailTemplate.java b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/AlertsEmailTemplate.java
index a66444ad838..2ea0faf34f2 100644
--- a/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/AlertsEmailTemplate.java
+++ b/plugins/sonar-email-notifications-plugin/src/main/java/org/sonar/plugins/emailnotifications/AlertsEmailTemplate.java
@@ -65,7 +65,7 @@ public class AlertsEmailTemplate extends EmailTemplate {
.setMessage(messageBody);
}
- private String generateSubject(String projectName, String alertLevel, boolean isNewAlert) {
+ private static String generateSubject(String projectName, String alertLevel, boolean isNewAlert) {
StringBuilder subjectBuilder = new StringBuilder();
if (Metric.Level.OK.toString().equals(alertLevel)) {
subjectBuilder.append("\"").append(projectName).append("\" is back to green");
diff --git a/pom.xml b/pom.xml
index 948dbf37af1..c4802f0fcd5 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1159,8 +1159,8 @@
</scm>
<ciManagement>
- <system>bamboo</system>
- <url>http://bamboo.ci.codehaus.org/browse/SONAR-DEF</url>
+ <system>travis-ci</system>
+ <url>https://travis-ci.org/SonarSource/sonarqube</url>
</ciManagement>
<licenses>
diff --git a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java
index 4919aa890d4..d4bad3f9b50 100644
--- a/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java
+++ b/server/sonar-server-benchmarks/src/test/java/org/sonar/server/benchmark/PersistFileSourcesStepTest.java
@@ -33,8 +33,9 @@ import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.DbComponentsRefCache.DbComponent;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.computation.step.PersistFileSourcesStep;
import org.sonar.server.db.DbClient;
import org.sonar.server.source.db.FileSourceDao;
@@ -49,12 +50,15 @@ public class PersistFileSourcesStepTest {
public static final int NUMBER_OF_LINES = 1000;
public static final String PROJECT_UUID = Uuids.create();
- DbComponentsRefCache dbComponentsRefCache = new DbComponentsRefCache();
-
@Rule
public DbTester dbTester = new DbTester();
+
@Rule
public Benchmark benchmark = new Benchmark();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
@@ -70,7 +74,7 @@ public class PersistFileSourcesStepTest {
long start = System.currentTimeMillis();
- PersistFileSourcesStep step = new PersistFileSourcesStep(dbClient, System2.INSTANCE, dbComponentsRefCache, reportReader);
+ PersistFileSourcesStep step = new PersistFileSourcesStep(dbClient, System2.INSTANCE, treeRootHolder, reportReader);
step.execute();
long end = System.currentTimeMillis();
@@ -92,17 +96,17 @@ public class PersistFileSourcesStepTest {
.setRef(1)
.setType(Constants.ComponentType.PROJECT);
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, "PROJECT", PROJECT_UUID));
-
+ List<Component> components = new ArrayList<>();
for (int fileRef = 2; fileRef <= NUMBER_OF_FILES + 1; fileRef++) {
- generateFileReport(fileRef);
+ components.add(generateFileReport(fileRef));
project.addChildRef(fileRef);
}
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, PROJECT_UUID, "PROJECT", components.toArray(new Component[components.size()])));
reportReader.putComponent(project.build());
}
- private void generateFileReport(int fileRef) throws IOException {
+ private Component generateFileReport(int fileRef) throws IOException {
LineData lineData = new LineData();
for (int line = 1; line <= NUMBER_OF_LINES; line++) {
lineData.generateLineData(line);
@@ -113,14 +117,14 @@ public class PersistFileSourcesStepTest {
.setLines(NUMBER_OF_LINES)
.build());
- dbComponentsRefCache.addComponent(fileRef, new DbComponent((long) fileRef, "PROJECT:" + fileRef, Uuids.create()));
-
reportReader.putFileSourceLines(fileRef, lineData.lines);
reportReader.putCoverage(fileRef, lineData.coverages);
reportReader.putChangesets(lineData.changesetsBuilder.setComponentRef(fileRef).build());
reportReader.putSyntaxHighlighting(fileRef, lineData.highlightings);
reportReader.putSymbols(fileRef, lineData.symbols);
reportReader.putDuplications(fileRef, lineData.duplications);
+
+ return new DumbComponent(Component.Type.FILE, fileRef, Uuids.create(), "PROJECT:" + fileRef);
}
private static class LineData {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/GlobalAction.java b/server/sonar-server/src/main/java/org/sonar/server/batch/GlobalAction.java
index 23956d9bbba..c87da9be3a7 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/batch/GlobalAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/batch/GlobalAction.java
@@ -80,7 +80,6 @@ public class GlobalAction implements BatchWsAction {
private void addMetrics(GlobalRepositories ref, DbSession session) {
for (MetricDto metric : dbClient.metricDao().selectEnabled(session)) {
- Boolean optimizedBestValue = metric.isOptimizedBestValue();
ref.addMetric(
new org.sonar.batch.protocol.input.Metric(metric.getId(), metric.getKey(),
metric.getValueType(),
@@ -91,7 +90,7 @@ public class GlobalAction implements BatchWsAction {
metric.isUserManaged(),
metric.getWorstValue(),
metric.getBestValue(),
- optimizedBestValue != null ? optimizedBestValue : false));
+ metric.isOptimizedBestValue()));
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java
index bd699806a7e..5906dd51515 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/batch/ProjectRepositoryLoader.java
@@ -24,6 +24,12 @@ import com.google.common.base.Function;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
+import java.util.Collections;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
import org.sonar.api.resources.Language;
import org.sonar.api.resources.Languages;
import org.sonar.api.rule.RuleKey;
@@ -54,14 +60,6 @@ import org.sonar.server.search.QueryContext;
import org.sonar.server.search.Result;
import org.sonar.server.user.UserSession;
-import javax.annotation.Nullable;
-
-import java.util.Collections;
-import java.util.Date;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
@@ -188,7 +186,7 @@ public class ProjectRepositoryLoader {
}
}
- private Map<String, String> getPropertiesMap(List<PropertyDto> propertyDtos, boolean hasScanPerm) {
+ private static Map<String, String> getPropertiesMap(List<PropertyDto> propertyDtos, boolean hasScanPerm) {
Map<String, String> properties = newHashMap();
for (PropertyDto propertyDto : propertyDtos) {
String key = propertyDto.getKey();
@@ -292,7 +290,7 @@ public class ProjectRepositoryLoader {
}
}
- private void addFileData(DbSession session, ProjectRepositories ref, List<ComponentDto> moduleChildren, List<FilePathWithHashDto> files) {
+ private static void addFileData(DbSession session, ProjectRepositories ref, List<ComponentDto> moduleChildren, List<FilePathWithHashDto> files) {
Map<String, String> moduleKeysByUuid = newHashMap();
for (ComponentDto module : moduleChildren) {
moduleKeysByUuid.put(module.uuid(), module.key());
@@ -320,7 +318,7 @@ public class ProjectRepositoryLoader {
}
}
- private Map<String, String> moduleUuidsByKey(ComponentDto module, List<ComponentDto> moduleChildren) {
+ private static Map<String, String> moduleUuidsByKey(ComponentDto module, List<ComponentDto> moduleChildren) {
Map<String, String> moduleUuidsByKey = newHashMap();
for (ComponentDto componentDto : moduleChildren) {
moduleUuidsByKey.put(componentDto.key(), componentDto.uuid());
@@ -328,7 +326,7 @@ public class ProjectRepositoryLoader {
return moduleUuidsByKey;
}
- private Map<String, Long> moduleIdsByKey(ComponentDto module, List<ComponentDto> moduleChildren) {
+ private static Map<String, Long> moduleIdsByKey(ComponentDto module, List<ComponentDto> moduleChildren) {
Map<String, Long> moduleIdsByKey = newHashMap();
for (ComponentDto componentDto : moduleChildren) {
moduleIdsByKey.put(componentDto.key(), componentDto.getId());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/DefaultComponentFinder.java b/server/sonar-server/src/main/java/org/sonar/server/component/DefaultComponentFinder.java
index 409cbc84208..698c46a57f7 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/DefaultComponentFinder.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/DefaultComponentFinder.java
@@ -22,15 +22,14 @@ package org.sonar.server.component;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
import com.google.common.collect.Sets;
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
import org.sonar.api.component.Component;
import org.sonar.api.utils.Paging;
import org.sonar.api.utils.log.Logger;
import org.sonar.api.utils.log.Loggers;
-import java.util.Collection;
-import java.util.List;
-import java.util.Set;
-
import static com.google.common.collect.Lists.newArrayList;
/**
@@ -98,7 +97,7 @@ public class DefaultComponentFinder {
}
}
- private Collection<? extends Component> pagedComponents(Collection<? extends Component> components, Paging paging) {
+ private static Collection<? extends Component> pagedComponents(Collection<? extends Component> components, Paging paging) {
Set<Component> pagedComponents = Sets.newLinkedHashSet();
int index = 0;
for (Component component : components) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/AppAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/AppAction.java
index 1609cfd1282..95d920b3a04 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/AppAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/AppAction.java
@@ -20,6 +20,10 @@
package org.sonar.server.component.ws;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.commons.lang.BooleanUtils;
import org.sonar.api.i18n.I18n;
import org.sonar.api.measures.CoreMetrics;
@@ -41,12 +45,6 @@ import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
-
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
@@ -149,7 +147,7 @@ public class AppAction implements RequestHandler {
json.prop("fav", isFavourite);
}
- private void appendPermissions(JsonWriter json, ComponentDto component, UserSession userSession) {
+ private static void appendPermissions(JsonWriter json, ComponentDto component, UserSession userSession) {
boolean hasBrowsePermission = userSession.hasComponentPermission(UserRole.USER, component.key());
json.prop("canMarkAsFavourite", userSession.isLoggedIn() && hasBrowsePermission);
json.prop("canCreateManualIssue", userSession.isLoggedIn() && hasBrowsePermission);
@@ -168,7 +166,7 @@ public class AppAction implements RequestHandler {
json.endObject();
}
- private MeasureDto coverageMeasure(Map<String, MeasureDto> measuresByMetricKey) {
+ private static MeasureDto coverageMeasure(Map<String, MeasureDto> measuresByMetricKey) {
MeasureDto overallCoverage = measuresByMetricKey.get(CoreMetrics.OVERALL_COVERAGE_KEY);
MeasureDto itCoverage = measuresByMetricKey.get(CoreMetrics.IT_COVERAGE_KEY);
MeasureDto utCoverage = measuresByMetricKey.get(CoreMetrics.COVERAGE_KEY);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/EventsWs.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/EventsWs.java
index 8f566aff6d2..f6e2501c5a1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/EventsWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/EventsWs.java
@@ -36,7 +36,7 @@ public class EventsWs implements WebService {
controller.done();
}
- private void defineIndexAction(NewController controller) {
+ private static void defineIndexAction(NewController controller) {
controller.createAction("index")
.setDescription("Documentation of this web service is available <a href=\"http://redirect.sonarsource.com/doc/old-web-service-api.html\">here</a>")
.setSince("2.6")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java
index 1d1256f9af3..3b398223e33 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/component/ws/SearchAction.java
@@ -120,7 +120,7 @@ public class SearchAction implements RequestHandler {
json.close();
}
- private Set<Long> pagedProjectIds(Collection<Long> projectIds, SearchOptions options) {
+ private static Set<Long> pagedProjectIds(Collection<Long> projectIds, SearchOptions options) {
Set<Long> results = Sets.newLinkedHashSet();
int index = 0;
for (Long projectId : projectIds) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java
index 6477b7aa6a2..e6e3556393b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImpl.java
@@ -22,7 +22,7 @@ package org.sonar.server.computation.batch;
import java.io.File;
import java.util.Objects;
-public class BatchReportDirectoryHolderImpl implements BatchReportDirectoryHolder, MutableBatchReportDirectoryHolder {
+public class BatchReportDirectoryHolderImpl implements MutableBatchReportDirectoryHolder {
private File directory;
@Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java
index 13cb2d6f960..c48e0289b1a 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/batch/BatchReportReaderImpl.java
@@ -125,38 +125,45 @@ public class BatchReportReaderImpl implements BatchReportReader {
public CloseableIterator<String> readFileSource(int fileRef) {
File file = delegate.readFileSource(fileRef);
if (file == null) {
- throw new IllegalStateException("Unable to find source for file #" + fileRef + ". File does not exist: " + file);
+ throw new IllegalStateException("Unable to find source for file #" + fileRef);
}
try {
- final LineIterator lineIterator = IOUtils.lineIterator(FileUtils.openInputStream(file), StandardCharsets.UTF_8);
- return new CloseableIterator<String>() {
- @Override
- public boolean hasNext() {
- return lineIterator.hasNext();
- }
-
- @Override
- public String next() {
- return lineIterator.next();
- }
-
- @Override
- protected String doNext() {
- // never called anyway
- throw new NoSuchElementException("Empty closeable Iterator has no element");
- }
-
- @Override
- protected void doClose() throws Exception {
- lineIterator.close();
- }
- };
+ return new CloseableLineIterator(IOUtils.lineIterator(FileUtils.openInputStream(file), StandardCharsets.UTF_8));
} catch (IOException e) {
throw new IllegalStateException("Fail to traverse file: " + file, e);
}
}
+ private static class CloseableLineIterator extends CloseableIterator<String> {
+ private final LineIterator lineIterator;
+
+ public CloseableLineIterator(LineIterator lineIterator) {
+ this.lineIterator = lineIterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return lineIterator.hasNext();
+ }
+
+ @Override
+ public String next() {
+ return lineIterator.next();
+ }
+
+ @Override
+ protected String doNext() {
+ // never called anyway
+ throw new NoSuchElementException("Empty closeable Iterator has no element");
+ }
+
+ @Override
+ protected void doClose() throws Exception {
+ lineIterator.close();
+ }
+ }
+
@Override
public CloseableIterator<BatchReport.Test> readTests(int testFileRef) {
File file = delegate.readTests(testFileRef);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java
index cefa2dfa615..ac25a24b155 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/Component.java
@@ -53,7 +53,9 @@ public interface Component {
*/
String getKey();
- // FIXME we should not expose a batch specific information
+ /**
+ * The component ref in the batch report.
+ */
int getRef();
List<Component> getChildren();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java
index f5f1d5ba0bb..3e2e8f6a484 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/ComponentImpl.java
@@ -31,7 +31,7 @@ import static com.google.common.collect.Iterables.filter;
public class ComponentImpl implements Component {
private final Type type;
- private final BatchReport.Component component;
+ private final int ref;
private final List<Component> children;
// Mutable values
@@ -39,7 +39,7 @@ public class ComponentImpl implements Component {
private String uuid;
public ComponentImpl(BatchReport.Component component, @Nullable Iterable<Component> children) {
- this.component = component;
+ this.ref = component.getRef();
this.type = convertType(component.getType());
this.children = children == null ? Collections.<Component>emptyList() : copyOf(filter(children, notNull()));
}
@@ -66,9 +66,10 @@ public class ComponentImpl implements Component {
@Override
public int getRef() {
- return component.getRef();
+ return ref;
}
+ @Override
public String getUuid() {
if (uuid == null) {
throw new UnsupportedOperationException(String.format("Component uuid of ref '%s' has not be fed yet", getRef()));
@@ -81,6 +82,7 @@ public class ComponentImpl implements Component {
return this;
}
+ @Override
public String getKey() {
if (key == null) {
throw new UnsupportedOperationException(String.format("Component key of ref '%s' has not be fed yet", getRef()));
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/DbComponentsRefCache.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/DbIdsRepository.java
index 3c9dda687f4..a07059b1e43 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/DbComponentsRefCache.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/DbIdsRepository.java
@@ -24,53 +24,33 @@ import java.util.HashMap;
import java.util.Map;
/**
- * Cache of components (id, uuid and key) that can be used in the persistence steps
- * Snapshot id will also be added in this cache
+ * Cache of persisted component (component id) that can be used in the persistence steps
*/
-public class DbComponentsRefCache {
+public class DbIdsRepository {
- private final Map<Integer, DbComponent> componentsByRef;
+ private final Map<Integer, Long> componentIdsByRef;
- public DbComponentsRefCache() {
- componentsByRef = new HashMap<>();
+ public DbIdsRepository() {
+ componentIdsByRef = new HashMap<>();
}
- public DbComponentsRefCache addComponent(Integer ref, DbComponent component) {
- componentsByRef.put(ref, component);
+ public DbIdsRepository setComponentId(Component component, long componentId) {
+ int ref = component.getRef();
+ Long existingComponentId = componentIdsByRef.get(ref);
+ if (existingComponentId != null) {
+ throw new IllegalArgumentException(String.format("Component ref '%s' has already a component id", ref));
+ }
+ componentIdsByRef.put(ref, componentId);
return this;
}
- public DbComponent getByRef(Integer ref) {
- DbComponent component = componentsByRef.get(ref);
- if (component == null) {
- throw new IllegalArgumentException(String.format("Component ref '%s' does not exists", ref));
+ public long getComponentId(Component component) {
+ int ref = component.getRef();
+ Long componentId = componentIdsByRef.get(ref);
+ if (componentId == null) {
+ throw new IllegalArgumentException(String.format("Component ref '%s' has no component id", ref));
}
- return componentsByRef.get(ref);
+ return componentId;
}
- public static class DbComponent {
-
- private Long id;
- private String uuid;
- private String key;
-
- public DbComponent(Long id, String key, String uuid) {
- this.id = id;
- this.key = key;
- this.uuid = uuid;
- }
-
- public Long getId() {
- return id;
- }
-
- public String getKey() {
- return key;
- }
-
- public String getUuid() {
- return uuid;
- }
-
- }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java
index c368b15bccc..4f4dc144870 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/DepthTraversalTypeAwareVisitor.java
@@ -43,17 +43,17 @@ public abstract class DepthTraversalTypeAwareVisitor implements TypeAwareVisitor
}
if (order == Order.PRE_ORDER) {
- visitNode(component);
+ visitAny(component);
}
visitChildren(component);
if (order == Order.POST_ORDER) {
- visitNode(component);
+ visitAny(component);
}
}
- private void visitNode(Component component) {
+ protected void visitAny(Component component) {
switch (component.getType()) {
case PROJECT:
visitProject(component);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolder.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolder.java
index 4b990fc9845..6d6d03348e6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolder.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolder.java
@@ -26,4 +26,12 @@ public interface TreeRootHolder {
* @throws IllegalStateException if the holder is empty (ie. there is no root yet)
*/
Component getRoot();
+
+ /**
+ * Return a component by its batch reference
+ *
+ * @throws IllegalStateException if the holder is empty (ie. there is no root yet)
+ * @throws IllegalArgumentException if there's no component for the reference
+ */
+ Component getComponentByRef(int ref);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java
index 1be5c91b1b0..fc0aee4129c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/component/TreeRootHolderImpl.java
@@ -19,24 +19,54 @@
*/
package org.sonar.server.computation.component;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+
/**
* Holds the reference to the root of the {@link Component} tree for the current CE run.
*/
public class TreeRootHolderImpl implements MutableTreeRootHolder {
+
private Component root;
+ private Map<Integer, Component> componentsByRef = new HashMap<>();
@Override
public void setRoot(Component newRoot) {
this.root = Objects.requireNonNull(newRoot);
+ feedComponentsByRef();
}
@Override
public Component getRoot() {
+ checkRoot();
+ return this.root;
+ }
+
+ @Override
+ public Component getComponentByRef(int ref) {
+ checkRoot();
+ Component component = componentsByRef.get(ref);
+ if (component == null) {
+ throw new IllegalArgumentException(String.format("Component '%s' hasn't been found", ref));
+ }
+ return component;
+ }
+
+ private void checkRoot() {
if (this.root == null) {
throw new IllegalStateException("Root has not been created yet");
}
- return this.root;
+ }
+
+ private void feedComponentsByRef() {
+ new DepthTraversalTypeAwareVisitor(Component.Type.FILE, POST_ORDER) {
+ @Override
+ public void visitAny(Component component) {
+ componentsByRef.put(component.getRef(), component);
+ }
+ }.visit(root);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
index 2c96179620d..897160138c1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/container/ComputeEngineContainerImpl.java
@@ -36,7 +36,7 @@ import org.sonar.server.computation.ReportQueue;
import org.sonar.server.computation.activity.ActivityManager;
import org.sonar.server.computation.batch.BatchReportDirectoryHolderImpl;
import org.sonar.server.computation.batch.BatchReportReaderImpl;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.DbIdsRepository;
import org.sonar.server.computation.component.ProjectSettingsRepository;
import org.sonar.server.computation.component.TreeRootHolderImpl;
import org.sonar.server.computation.event.EventRepositoryImpl;
@@ -126,7 +126,7 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co
ProjectSettingsRepository.class,
// component caches
- DbComponentsRefCache.class,
+ DbIdsRepository.class,
// issues
ScmAccountCacheLoader.class,
@@ -147,20 +147,18 @@ public class ComputeEngineContainerImpl extends ComponentContainer implements Co
);
}
+ @Override
public void process() {
// calls the first
getComponentByType(ComputationService.class).process();
}
+ @Override
public void cleanup() {
- ReportQueue.Item item = null;
try {
- item = getComponentByType(ReportQueue.Item.class);
stopComponents();
} catch (Throwable t) {
- Loggers.get(ComputeEngineContainerImpl.class).error(
- String.format("Cleanup of container for item '%s' failed", item == null ? null : item.dto),
- t);
+ Loggers.get(ComputeEngineContainerImpl.class).error(String.format("Cleanup of container for item '%s' failed", item), t);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java
index 61718b66689..ed9f648bab0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/measure/MeasureRepositoryImpl.java
@@ -44,8 +44,6 @@ public class MeasureRepositoryImpl implements MeasureRepository {
public Optional<MeasureDto> findPrevious(Component component, Metric<?> metric) {
try (DbSession dbSession = dbClient.openSession(false)) {
return Optional.fromNullable(
- // TODO replace component.getKey() by ${link #getKey} as component.getKey() is only for project/module and does not take into
- // account usage of the branch
dbClient.measureDao().findByComponentKeyAndMetricKey(dbSession, component.getKey(), metric.getKey())
);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java b/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java
index db57bcb52c8..ce8bdf2c609 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/source/SymbolsLineReader.java
@@ -20,9 +20,6 @@
package org.sonar.server.computation.source;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.server.source.db.FileSourceDb;
-
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
@@ -32,6 +29,8 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.source.db.FileSourceDb;
import static com.google.common.collect.Lists.newArrayList;
@@ -68,7 +67,7 @@ public class SymbolsLineReader implements LineReader {
}
}
- private void appendSymbol(StringBuilder lineSymbol, BatchReport.Range range, int line, int symbolId, String sourceLine) {
+ private static void appendSymbol(StringBuilder lineSymbol, BatchReport.Range range, int line, int symbolId, String sourceLine) {
if (matchLine(range, line)) {
String offsets = RangeOffsetHelper.offsetToString(range, line, sourceLine.length());
if (!offsets.isEmpty()) {
@@ -105,7 +104,7 @@ public class SymbolsLineReader implements LineReader {
return range.getStartLine() <= line && range.getEndLine() >= line;
}
- private Map<BatchReport.Symbols.Symbol, Integer> createIdsBySymbolMap(List<BatchReport.Symbols.Symbol> symbols) {
+ private static Map<BatchReport.Symbols.Symbol, Integer> createIdsBySymbolMap(List<BatchReport.Symbols.Symbol> symbols) {
Map<BatchReport.Symbols.Symbol, Integer> map = new HashMap<>();
int symbolId = 1;
for (BatchReport.Symbols.Symbol symbol : symbols) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ApplyPermissionsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ApplyPermissionsStep.java
index e67e6b15809..0b30dbf19e5 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ApplyPermissionsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ApplyPermissionsStep.java
@@ -24,7 +24,7 @@ import org.sonar.api.resources.Qualifiers;
import org.sonar.core.permission.PermissionFacade;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.DbIdsRepository;
import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
import org.sonar.server.issue.index.IssueAuthorizationIndexer;
@@ -35,15 +35,15 @@ import org.sonar.server.issue.index.IssueAuthorizationIndexer;
public class ApplyPermissionsStep implements ComputationStep {
private final DbClient dbClient;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final DbIdsRepository dbIdsRepository;
private final IssueAuthorizationIndexer indexer;
private final PermissionFacade permissionFacade;
private final TreeRootHolder treeRootHolder;
- public ApplyPermissionsStep(DbClient dbClient, DbComponentsRefCache dbComponentsRefCache, IssueAuthorizationIndexer indexer,
+ public ApplyPermissionsStep(DbClient dbClient, DbIdsRepository dbIdsRepository, IssueAuthorizationIndexer indexer,
PermissionFacade permissionFacade, TreeRootHolder treeRootHolder) {
this.dbClient = dbClient;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.dbIdsRepository = dbIdsRepository;
this.indexer = indexer;
this.permissionFacade = permissionFacade;
this.treeRootHolder = treeRootHolder;
@@ -53,7 +53,7 @@ public class ApplyPermissionsStep implements ComputationStep {
public void execute() {
DbSession session = dbClient.openSession(false);
try {
- long projectId = dbComponentsRefCache.getByRef(treeRootHolder.getRoot().getRef()).getId();
+ long projectId = dbIdsRepository.getComponentId(treeRootHolder.getRoot());
if (permissionFacade.countComponentPermissions(session, projectId) == 0) {
permissionFacade.grantDefaultRoles(session, projectId, Qualifiers.PROJECT);
session.commit();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
index a967fd10526..25190675f4c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ComputationSteps.java
@@ -52,7 +52,7 @@ public class ComputationSteps {
QualityProfileEventsStep.class,
// Persist data
- PersistComponentsStep.class,
+ PersistComponentsAndSnapshotsStep.class,
PersistNumberOfDaysSinceLastCommitStep.class,
PersistMeasuresStep.class,
PersistIssuesStep.class,
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexComponentsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexComponentsStep.java
index 75b8d6acb2b..53285259121 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexComponentsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexComponentsStep.java
@@ -21,26 +21,27 @@
package org.sonar.server.computation.step;
import org.sonar.core.resource.ResourceIndexerDao;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.TreeRootHolder;
/**
* Components are currently indexed in db table RESOURCE_INDEX, not in Elasticsearch
*/
public class IndexComponentsStep implements ComputationStep {
+
private final ResourceIndexerDao resourceIndexerDao;
- private final DbComponentsRefCache dbComponentsRefCache;
- private final BatchReportReader reportReader;
+ private final DbIdsRepository dbIdsRepository;
+ private final TreeRootHolder treeRootHolder;
- public IndexComponentsStep(ResourceIndexerDao resourceIndexerDao, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ public IndexComponentsStep(ResourceIndexerDao resourceIndexerDao, DbIdsRepository dbIdsRepository, TreeRootHolder treeRootHolder) {
this.resourceIndexerDao = resourceIndexerDao;
- this.dbComponentsRefCache = dbComponentsRefCache;
- this.reportReader = reportReader;
+ this.dbIdsRepository = dbIdsRepository;
+ this.treeRootHolder = treeRootHolder;
}
@Override
public void execute() {
- resourceIndexerDao.indexProject(dbComponentsRefCache.getByRef(reportReader.readMetadata().getRootComponentRef()).getId());
+ resourceIndexerDao.indexProject(dbIdsRepository.getComponentId(treeRootHolder.getRoot()));
}
@Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java
index ee709b8e154..237871065bf 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexSourceLinesStep.java
@@ -19,25 +19,22 @@
*/
package org.sonar.server.computation.step;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.source.index.SourceLineIndexer;
public class IndexSourceLinesStep implements ComputationStep {
private final SourceLineIndexer indexer;
- private final DbComponentsRefCache dbComponentsRefCache;
- private final BatchReportReader reportReader;
+ private final TreeRootHolder treeRootHolder;
- public IndexSourceLinesStep(SourceLineIndexer indexer, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ public IndexSourceLinesStep(SourceLineIndexer indexer, TreeRootHolder treeRootHolder) {
this.indexer = indexer;
- this.dbComponentsRefCache = dbComponentsRefCache;
- this.reportReader = reportReader;
+ this.treeRootHolder = treeRootHolder;
}
@Override
public void execute() {
- indexer.index(dbComponentsRefCache.getByRef(reportReader.readMetadata().getRootComponentRef()).getUuid());
+ indexer.index(treeRootHolder.getRoot().getUuid());
}
@Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexTestsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexTestsStep.java
index bd5666e539a..663b0c2030e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexTestsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/IndexTestsStep.java
@@ -20,25 +20,22 @@
package org.sonar.server.computation.step;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.test.index.TestIndexer;
public class IndexTestsStep implements ComputationStep {
private final TestIndexer indexer;
- private final DbComponentsRefCache dbComponentsRefCache;
- private final BatchReportReader reportReader;
+ private final TreeRootHolder treeRootHolder;
- public IndexTestsStep(TestIndexer indexer, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ public IndexTestsStep(TestIndexer indexer, TreeRootHolder treeRootHolder) {
this.indexer = indexer;
- this.dbComponentsRefCache = dbComponentsRefCache;
- this.reportReader = reportReader;
+ this.treeRootHolder = treeRootHolder;
}
@Override
public void execute() {
- indexer.index(dbComponentsRefCache.getByRef(reportReader.readMetadata().getRootComponentRef()).getUuid());
+ indexer.index(treeRootHolder.getRoot().getUuid());
}
@Override
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsAndSnapshotsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsAndSnapshotsStep.java
new file mode 100644
index 00000000000..844f00e3e2f
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsAndSnapshotsStep.java
@@ -0,0 +1,346 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.step;
+
+import com.google.common.collect.Maps;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.lang.ObjectUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.resources.Qualifiers;
+import org.sonar.api.resources.Scopes;
+import org.sonar.api.utils.System2;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.core.component.ComponentDto;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.util.NonNullInputFunction;
+import org.sonar.server.computation.batch.BatchReportReader;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.TreeRootHolder;
+import org.sonar.server.db.DbClient;
+
+/**
+ * Persist components and snapshots
+ * Also feed the components cache {@link DbIdsRepository}
+ */
+public class PersistComponentsAndSnapshotsStep implements ComputationStep {
+
+ private final System2 system2;
+ private final DbClient dbClient;
+ private final TreeRootHolder treeRootHolder;
+ private final BatchReportReader reportReader;
+
+ private final DbIdsRepository dbIdsRepositor;
+
+ public PersistComponentsAndSnapshotsStep(System2 system2, DbClient dbClient, TreeRootHolder treeRootHolder, BatchReportReader reportReader, DbIdsRepository dbIdsRepositor) {
+ this.system2 = system2;
+ this.dbClient = dbClient;
+ this.treeRootHolder = treeRootHolder;
+ this.reportReader = reportReader;
+ this.dbIdsRepositor = dbIdsRepositor;
+ }
+
+ @Override
+ public void execute() {
+ DbSession session = dbClient.openSession(false);
+ try {
+ org.sonar.server.computation.component.Component root = treeRootHolder.getRoot();
+ List<ComponentDto> components = dbClient.componentDao().selectComponentsFromProjectKey(session, root.getKey());
+ Map<String, ComponentDto> componentDtosByKey = componentDtosByKey(components);
+ PersisComponentExecutor componentContext = new PersisComponentExecutor(session, componentDtosByKey, reportReader, reportReader.readMetadata().getAnalysisDate());
+
+ componentContext.recursivelyProcessComponent(root, null, null);
+ session.commit();
+ } finally {
+ session.close();
+ }
+ }
+
+ private class PersisComponentExecutor {
+
+ private final BatchReportReader reportReader;
+ private final Map<String, ComponentDto> componentDtosByKey;
+ private final DbSession dbSession;
+ private final long analysisDate;
+
+ private ComponentDto project;
+ private SnapshotDto projectSnapshot;
+
+ public PersisComponentExecutor(DbSession dbSession, Map<String, ComponentDto> componentDtosByKey, BatchReportReader reportReader, long analysisDate) {
+ this.reportReader = reportReader;
+ this.componentDtosByKey = componentDtosByKey;
+ this.dbSession = dbSession;
+ this.analysisDate = analysisDate;
+ }
+
+ private void recursivelyProcessComponent(Component component, @Nullable ComponentDto lastModule, @Nullable SnapshotDto parentSnapshot) {
+ BatchReport.Component reportComponent = reportReader.readComponent(component.getRef());
+
+ switch (component.getType()) {
+ case PROJECT:
+ PersistedComponent persistedProject = processProject(component, reportComponent);
+ this.project = persistedProject.componentDto;
+ this.projectSnapshot = persistedProject.parentSnapshot;
+ processChildren(component, project, persistedProject.parentSnapshot);
+ break;
+ case MODULE:
+ PersistedComponent persistedModule = processModule(component, reportComponent, nonNullLastModule(lastModule), nonNullParentSnapshot(parentSnapshot));
+ processChildren(component, persistedModule.componentDto, persistedModule.parentSnapshot);
+ break;
+ case DIRECTORY:
+ PersistedComponent persistedDirectory = processDirectory(component, reportComponent, nonNullLastModule(lastModule), nonNullParentSnapshot(parentSnapshot));
+ processChildren(component, nonNullLastModule(lastModule), persistedDirectory.parentSnapshot);
+ break;
+ case FILE:
+ processFile(component, reportComponent, nonNullLastModule(lastModule), nonNullParentSnapshot(parentSnapshot));
+ break;
+ default:
+ throw new IllegalStateException(String.format("Unsupported component type '%s'", component.getType()));
+ }
+ }
+
+ private void processChildren(Component component, ComponentDto lastModule, SnapshotDto parentSnapshot) {
+ for (Component child : component.getChildren()) {
+ recursivelyProcessComponent(child, lastModule, parentSnapshot);
+ }
+ }
+
+ private ComponentDto nonNullLastModule(@Nullable ComponentDto lastModule) {
+ return lastModule == null ? project : lastModule;
+ }
+
+ private SnapshotDto nonNullParentSnapshot(@Nullable SnapshotDto parentSnapshot) {
+ return parentSnapshot == null ? projectSnapshot : parentSnapshot;
+ }
+
+ public PersistedComponent processProject(Component project, BatchReport.Component reportComponent) {
+ ComponentDto componentDto = createComponentDto(reportComponent, project);
+
+ componentDto.setScope(Scopes.PROJECT);
+ componentDto.setQualifier(Qualifiers.PROJECT);
+ componentDto.setName(reportComponent.getName());
+ componentDto.setLongName(componentDto.name());
+ if (reportComponent.hasDescription()) {
+ componentDto.setDescription(reportComponent.getDescription());
+ }
+ componentDto.setProjectUuid(componentDto.uuid());
+ componentDto.setModuleUuidPath(ComponentDto.MODULE_UUID_PATH_SEP + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP);
+
+ ComponentDto projectDto = persistComponent(project.getRef(), componentDto);
+ SnapshotDto snapshotDto = persistSnapshot(projectDto, reportComponent.getVersion(), null);
+
+ addToCache(project, projectDto, snapshotDto);
+
+ return new PersistedComponent(projectDto, snapshotDto);
+ }
+
+ public PersistedComponent processModule(Component module, BatchReport.Component reportComponent, ComponentDto lastModule, SnapshotDto parentSnapshot) {
+ ComponentDto componentDto = createComponentDto(reportComponent, module);
+
+ componentDto.setScope(Scopes.PROJECT);
+ componentDto.setQualifier(Qualifiers.MODULE);
+ componentDto.setName(reportComponent.getName());
+ componentDto.setLongName(componentDto.name());
+ if (reportComponent.hasPath()) {
+ componentDto.setPath(reportComponent.getPath());
+ }
+ if (reportComponent.hasDescription()) {
+ componentDto.setDescription(reportComponent.getDescription());
+ }
+ componentDto.setParentProjectId(project.getId());
+ componentDto.setProjectUuid(lastModule.projectUuid());
+ componentDto.setModuleUuid(lastModule.uuid());
+ componentDto.setModuleUuidPath(lastModule.moduleUuidPath() + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP);
+
+ ComponentDto moduleDto = persistComponent(module.getRef(), componentDto);
+ SnapshotDto snapshotDto = persistSnapshot(moduleDto, reportComponent.getVersion(), parentSnapshot);
+
+ addToCache(module, moduleDto, snapshotDto);
+ return new PersistedComponent(moduleDto, snapshotDto);
+ }
+
+ public PersistedComponent processDirectory(org.sonar.server.computation.component.Component directory, BatchReport.Component reportComponent,
+ ComponentDto lastModule, SnapshotDto parentSnapshot) {
+ ComponentDto componentDto = createComponentDto(reportComponent, directory);
+
+ componentDto.setScope(Scopes.DIRECTORY);
+ componentDto.setQualifier(Qualifiers.DIRECTORY);
+ componentDto.setName(reportComponent.getPath());
+ componentDto.setLongName(reportComponent.getPath());
+ if (reportComponent.hasPath()) {
+ componentDto.setPath(reportComponent.getPath());
+ }
+
+ componentDto.setParentProjectId(lastModule.getId());
+ componentDto.setProjectUuid(lastModule.projectUuid());
+ componentDto.setModuleUuid(lastModule.uuid());
+ componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
+
+ ComponentDto directoryDto = persistComponent(directory.getRef(), componentDto);
+ SnapshotDto snapshotDto = persistSnapshot(directoryDto, null, parentSnapshot);
+
+ addToCache(directory, directoryDto, snapshotDto);
+ return new PersistedComponent(directoryDto, snapshotDto);
+ }
+
+ public void processFile(org.sonar.server.computation.component.Component file, BatchReport.Component reportComponent,
+ ComponentDto lastModule, SnapshotDto parentSnapshot) {
+ ComponentDto componentDto = createComponentDto(reportComponent, file);
+
+ componentDto.setScope(Scopes.FILE);
+ componentDto.setQualifier(getFileQualifier(reportComponent));
+ componentDto.setName(FilenameUtils.getName(reportComponent.getPath()));
+ componentDto.setLongName(reportComponent.getPath());
+ if (reportComponent.hasPath()) {
+ componentDto.setPath(reportComponent.getPath());
+ }
+ if (reportComponent.hasLanguage()) {
+ componentDto.setLanguage(reportComponent.getLanguage());
+ }
+
+ componentDto.setParentProjectId(lastModule.getId());
+ componentDto.setProjectUuid(lastModule.projectUuid());
+ componentDto.setModuleUuid(lastModule.uuid());
+ componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
+
+ ComponentDto fileDto = persistComponent(file.getRef(), componentDto);
+ SnapshotDto snapshotDto = persistSnapshot(fileDto, null, parentSnapshot);
+
+ addToCache(file, fileDto, snapshotDto);
+ }
+
+ private ComponentDto createComponentDto(BatchReport.Component reportComponent, org.sonar.server.computation.component.Component component) {
+ String componentKey = component.getKey();
+ String componentUuid = component.getUuid();
+
+ ComponentDto componentDto = new ComponentDto();
+ componentDto.setUuid(componentUuid);
+ componentDto.setKey(componentKey);
+ componentDto.setDeprecatedKey(componentKey);
+ componentDto.setEnabled(true);
+ return componentDto;
+ }
+
+ private ComponentDto persistComponent(int componentRef, ComponentDto componentDto) {
+ ComponentDto existingComponent = componentDtosByKey.get(componentDto.getKey());
+ if (existingComponent == null) {
+ dbClient.componentDao().insert(dbSession, componentDto);
+ return componentDto;
+ } else {
+ if (updateComponent(existingComponent, componentDto)) {
+ dbClient.componentDao().update(dbSession, existingComponent);
+ }
+ return existingComponent;
+ }
+ }
+
+ private SnapshotDto persistSnapshot(ComponentDto componentDto, @Nullable String version, @Nullable SnapshotDto parentSnapshot){
+ SnapshotDto snapshotDto = new SnapshotDto();
+// .setRootProjectId(project.getId())
+// .setVersion(version)
+// .setComponentId(componentDto.getId())
+// .setQualifier(componentDto.qualifier())
+// .setScope(componentDto.scope())
+// .setCreatedAt(analysisDate)
+// .setBuildDate(system2.now());
+//
+// if (parentSnapshot != null) {
+// snapshotDto
+// .setParentId(parentSnapshot.getId())
+// .setRootId(parentSnapshot.getRootId() == null ? parentSnapshot.getId() : parentSnapshot.getRootId())
+// .setDepth(parentSnapshot.getDepth() + 1)
+// .setPath(parentSnapshot.getPath() + parentSnapshot.getId() + ".");
+// } else {
+// snapshotDto
+// .setPath("")
+// .setDepth(0);
+// }
+// dbClient.snapshotDao().insert(dbSession, snapshotDto);
+ return snapshotDto;
+ }
+
+ private void addToCache(Component component, ComponentDto componentDto, SnapshotDto snapshotDto) {
+ dbIdsRepositor.setComponentId(component, componentDto.getId());
+ }
+
+ private boolean updateComponent(ComponentDto existingComponent, ComponentDto newComponent) {
+ boolean isUpdated = false;
+ if (!StringUtils.equals(existingComponent.name(), newComponent.name())) {
+ existingComponent.setName(newComponent.name());
+ isUpdated = true;
+ }
+ if (!StringUtils.equals(existingComponent.description(), newComponent.description())) {
+ existingComponent.setDescription(newComponent.description());
+ isUpdated = true;
+ }
+ if (!StringUtils.equals(existingComponent.path(), newComponent.path())) {
+ existingComponent.setPath(newComponent.path());
+ isUpdated = true;
+ }
+ if (!StringUtils.equals(existingComponent.moduleUuid(), newComponent.moduleUuid())) {
+ existingComponent.setModuleUuid(newComponent.moduleUuid());
+ isUpdated = true;
+ }
+ if (!existingComponent.moduleUuidPath().equals(newComponent.moduleUuidPath())) {
+ existingComponent.setModuleUuidPath(newComponent.moduleUuidPath());
+ isUpdated = true;
+ }
+ if (!ObjectUtils.equals(existingComponent.parentProjectId(), newComponent.parentProjectId())) {
+ existingComponent.setParentProjectId(newComponent.parentProjectId());
+ isUpdated = true;
+ }
+ return isUpdated;
+ }
+
+ private String getFileQualifier(BatchReport.Component reportComponent) {
+ return reportComponent.getIsTest() ? Qualifiers.UNIT_TEST_FILE : Qualifiers.FILE;
+ }
+
+ private class PersistedComponent {
+ private ComponentDto componentDto;
+ private SnapshotDto parentSnapshot;
+
+ public PersistedComponent(ComponentDto componentDto, SnapshotDto parentSnapshot) {
+ this.componentDto = componentDto;
+ this.parentSnapshot = parentSnapshot;
+ }
+ }
+
+ }
+
+ private static Map<String, ComponentDto> componentDtosByKey(List<ComponentDto> components) {
+ return Maps.uniqueIndex(components, new NonNullInputFunction<ComponentDto, String>() {
+ @Override
+ public String doApply(ComponentDto input) {
+ return input.key();
+ }
+ });
+ }
+
+ @Override
+ public String getDescription() {
+ return "Feed components and snapshots";
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java
deleted file mode 100644
index 629b883697b..00000000000
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistComponentsStep.java
+++ /dev/null
@@ -1,260 +0,0 @@
-/*
- * SonarQube, open source software quality management tool.
- * Copyright (C) 2008-2014 SonarSource
- * mailto:contact AT sonarsource DOT com
- *
- * SonarQube is free software; you can redistribute it and/or
- * modify it under the terms of the GNU Lesser General Public
- * License as published by the Free Software Foundation; either
- * version 3 of the License, or (at your option) any later version.
- *
- * SonarQube is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * Lesser General Public License for more details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- */
-
-package org.sonar.server.computation.step;
-
-import com.google.common.collect.Maps;
-import java.util.List;
-import java.util.Map;
-import org.apache.commons.io.FilenameUtils;
-import org.apache.commons.lang.ObjectUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.resources.Qualifiers;
-import org.sonar.api.resources.Scopes;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.component.ComponentDto;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.util.NonNullInputFunction;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.TreeRootHolder;
-import org.sonar.server.db.DbClient;
-
-public class PersistComponentsStep implements ComputationStep {
-
- private final DbClient dbClient;
- private final DbComponentsRefCache dbComponentsRefCache;
- private final BatchReportReader reportReader;
- private final TreeRootHolder treeRootHolder;
-
- public PersistComponentsStep(DbClient dbClient, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader, TreeRootHolder treeRootHolder) {
- this.dbClient = dbClient;
- this.dbComponentsRefCache = dbComponentsRefCache;
- this.reportReader = reportReader;
- this.treeRootHolder = treeRootHolder;
- }
-
- @Override
- public void execute() {
- DbSession session = dbClient.openSession(false);
- try {
- Component root = treeRootHolder.getRoot();
- List<ComponentDto> components = dbClient.componentDao().selectComponentsFromProjectKey(session, root.getKey());
- Map<String, ComponentDto> componentDtosByKey = componentDtosByKey(components);
- ComponentContext componentContext = new ComponentContext(session, componentDtosByKey);
-
- ComponentDto projectDto = processProject(root, reportReader.readComponent(root.getRef()), componentContext);
- processChildren(componentContext, root, projectDto, projectDto);
- session.commit();
- } finally {
- session.close();
- }
- }
-
- private void recursivelyProcessComponent(ComponentContext componentContext, Component component, ComponentDto parentModule, ComponentDto project) {
- BatchReport.Component reportComponent = reportReader.readComponent(component.getRef());
-
- switch (component.getType()) {
- case MODULE:
- ComponentDto moduleDto = processModule(component, reportComponent, componentContext, parentModule, project.getId());
- processChildren(componentContext, component, moduleDto, project);
- break;
- case DIRECTORY:
- processDirectory(component, reportComponent, componentContext, parentModule, project.getId());
- processChildren(componentContext, component, parentModule, project);
- break;
- case FILE:
- processFile(component, reportComponent, componentContext, parentModule, project.getId());
- processChildren(componentContext, component, parentModule, project);
- break;
- default:
- throw new IllegalStateException(String.format("Unsupported component type '%s'", component.getType()));
- }
- }
-
- private void processChildren(ComponentContext componentContext, Component component, ComponentDto parentModule, ComponentDto project) {
- for (Component child : component.getChildren()) {
- recursivelyProcessComponent(componentContext, child, parentModule, project);
- }
- }
-
- public ComponentDto processProject(Component project, BatchReport.Component reportComponent, ComponentContext componentContext) {
- ComponentDto componentDto = createComponentDto(project);
-
- componentDto.setScope(Scopes.PROJECT);
- componentDto.setQualifier(Qualifiers.PROJECT);
- componentDto.setName(reportComponent.getName());
- componentDto.setLongName(componentDto.name());
- if (reportComponent.hasDescription()) {
- componentDto.setDescription(reportComponent.getDescription());
- }
- componentDto.setProjectUuid(componentDto.uuid());
- componentDto.setModuleUuidPath(ComponentDto.MODULE_UUID_PATH_SEP + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP);
-
- return persistComponent(project.getRef(), componentDto, componentContext);
- }
-
- public ComponentDto processModule(Component module, BatchReport.Component reportComponent, ComponentContext componentContext, ComponentDto lastModule, long projectId) {
- ComponentDto componentDto = createComponentDto(module);
-
- componentDto.setScope(Scopes.PROJECT);
- componentDto.setQualifier(Qualifiers.MODULE);
- componentDto.setName(reportComponent.getName());
- componentDto.setLongName(componentDto.name());
- if (reportComponent.hasPath()) {
- componentDto.setPath(reportComponent.getPath());
- }
- if (reportComponent.hasDescription()) {
- componentDto.setDescription(reportComponent.getDescription());
- }
- componentDto.setParentProjectId(projectId);
- componentDto.setProjectUuid(lastModule.projectUuid());
- componentDto.setModuleUuid(lastModule.uuid());
- componentDto.setModuleUuidPath((lastModule.moduleUuidPath() + componentDto.uuid() + ComponentDto.MODULE_UUID_PATH_SEP));
-
- return persistComponent(module.getRef(), componentDto, componentContext);
- }
-
- public void processDirectory(Component directory, BatchReport.Component reportComponent, ComponentContext componentContext, ComponentDto lastModule, long projectId) {
- ComponentDto componentDto = createComponentDto(directory);
-
- componentDto.setScope(Scopes.DIRECTORY);
- componentDto.setQualifier(Qualifiers.DIRECTORY);
- componentDto.setName(reportComponent.getPath());
- componentDto.setLongName(reportComponent.getPath());
- if (reportComponent.hasPath()) {
- componentDto.setPath(reportComponent.getPath());
- }
-
- componentDto.setParentProjectId(lastModule.getId());
- componentDto.setProjectUuid(lastModule.projectUuid());
- componentDto.setModuleUuid(lastModule.uuid());
- componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
-
- persistComponent(directory.getRef(), componentDto, componentContext);
- }
-
- public void processFile(Component file, BatchReport.Component reportComponent, ComponentContext componentContext, ComponentDto lastModule, long projectId) {
- ComponentDto componentDto = createComponentDto(file);
-
- componentDto.setScope(Scopes.FILE);
- componentDto.setQualifier(getFileQualifier(reportComponent));
- componentDto.setName(FilenameUtils.getName(reportComponent.getPath()));
- componentDto.setLongName(reportComponent.getPath());
- if (reportComponent.hasPath()) {
- componentDto.setPath(reportComponent.getPath());
- }
- if (reportComponent.hasLanguage()) {
- componentDto.setLanguage(reportComponent.getLanguage());
- }
-
- componentDto.setParentProjectId(lastModule.getId());
- componentDto.setProjectUuid(lastModule.projectUuid());
- componentDto.setModuleUuid(lastModule.uuid());
- componentDto.setModuleUuidPath(lastModule.moduleUuidPath());
-
- persistComponent(file.getRef(), componentDto, componentContext);
- }
-
- private ComponentDto createComponentDto(Component component) {
- String componentKey = component.getKey();
- String componentUuid = component.getUuid();
-
- ComponentDto componentDto = new ComponentDto();
- componentDto.setUuid(componentUuid);
- componentDto.setKey(componentKey);
- componentDto.setDeprecatedKey(componentKey);
- componentDto.setEnabled(true);
- return componentDto;
- }
-
- private ComponentDto persistComponent(int componentRef, ComponentDto componentDto, ComponentContext componentContext) {
- ComponentDto existingComponent = componentContext.componentDtosByKey.get(componentDto.getKey());
- if (existingComponent == null) {
- dbClient.componentDao().insert(componentContext.dbSession, componentDto);
- dbComponentsRefCache.addComponent(componentRef, new DbComponentsRefCache.DbComponent(componentDto.getId(), componentDto.getKey(), componentDto.uuid()));
- return componentDto;
- } else {
- if (updateComponent(existingComponent, componentDto)) {
- dbClient.componentDao().update(componentContext.dbSession, existingComponent);
- }
- dbComponentsRefCache.addComponent(componentRef, new DbComponentsRefCache.DbComponent(existingComponent.getId(), existingComponent.getKey(), existingComponent.uuid()));
- return existingComponent;
- }
- }
-
- private static boolean updateComponent(ComponentDto existingComponent, ComponentDto newComponent) {
- boolean isUpdated = false;
- if (!StringUtils.equals(existingComponent.name(), newComponent.name())) {
- existingComponent.setName(newComponent.name());
- isUpdated = true;
- }
- if (!StringUtils.equals(existingComponent.description(), newComponent.description())) {
- existingComponent.setDescription(newComponent.description());
- isUpdated = true;
- }
- if (!StringUtils.equals(existingComponent.path(), newComponent.path())) {
- existingComponent.setPath(newComponent.path());
- isUpdated = true;
- }
- if (!StringUtils.equals(existingComponent.moduleUuid(), newComponent.moduleUuid())) {
- existingComponent.setModuleUuid(newComponent.moduleUuid());
- isUpdated = true;
- }
- if (!existingComponent.moduleUuidPath().equals(newComponent.moduleUuidPath())) {
- existingComponent.setModuleUuidPath(newComponent.moduleUuidPath());
- isUpdated = true;
- }
- if (!ObjectUtils.equals(existingComponent.parentProjectId(), newComponent.parentProjectId())) {
- existingComponent.setParentProjectId(newComponent.parentProjectId());
- isUpdated = true;
- }
- return isUpdated;
- }
-
- private static String getFileQualifier(BatchReport.Component reportComponent) {
- return reportComponent.getIsTest() ? Qualifiers.UNIT_TEST_FILE : Qualifiers.FILE;
- }
-
- private Map<String, ComponentDto> componentDtosByKey(List<ComponentDto> components) {
- return Maps.uniqueIndex(components, new NonNullInputFunction<ComponentDto, String>() {
- @Override
- public String doApply(ComponentDto input) {
- return input.key();
- }
- });
- }
-
- private static class ComponentContext {
- private final Map<String, ComponentDto> componentDtosByKey;
- private final DbSession dbSession;
-
- public ComponentContext(DbSession dbSession, Map<String, ComponentDto> componentDtosByKey) {
- this.componentDtosByKey = componentDtosByKey;
- this.dbSession = dbSession;
- }
- }
-
- @Override
- public String getDescription() {
- return "Feed components cache";
- }
-}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
index 5cd1ae314cc..f635806afd1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistDuplicationsStep.java
@@ -30,21 +30,28 @@ import org.sonar.core.metric.db.MetricDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+
/**
* Persist duplications into
*/
public class PersistDuplicationsStep implements ComputationStep {
private final DbClient dbClient;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final DbIdsRepository dbIdsRepository;
+ private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
- public PersistDuplicationsStep(DbClient dbClient, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ public PersistDuplicationsStep(DbClient dbClient, DbIdsRepository dbIdsRepository, TreeRootHolder treeRootHolder, BatchReportReader reportReader) {
this.dbClient = dbClient;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.dbIdsRepository = dbIdsRepository;
+ this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
}
@@ -52,102 +59,89 @@ public class PersistDuplicationsStep implements ComputationStep {
public void execute() {
DbSession session = dbClient.openSession(true);
try {
- MetricDto duplicationMetric = dbClient.metricDao().selectNullableByKey(session, CoreMetrics.DUPLICATIONS_DATA_KEY);
- DuplicationContext duplicationContext = new DuplicationContext(duplicationMetric, session);
- int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
- recursivelyProcessComponent(duplicationContext, rootComponentRef);
+ MetricDto duplicationMetric = dbClient.metricDao().selectByKey(session, CoreMetrics.DUPLICATIONS_DATA_KEY);
+ new DuplicationVisitor(session, duplicationMetric).visit(treeRootHolder.getRoot());
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}
- private void recursivelyProcessComponent(DuplicationContext duplicationContext, int componentRef) {
- BatchReport.Component component = reportReader.readComponent(componentRef);
- List<BatchReport.Duplication> duplications = reportReader.readComponentDuplications(componentRef);
- if (!duplications.isEmpty()) {
- saveDuplications(duplicationContext, component, duplications);
- }
+ private class DuplicationVisitor extends DepthTraversalTypeAwareVisitor {
+
+ private final DbSession session;
+ private final MetricDto duplicationMetric;
- for (Integer childRef : component.getChildRefList()) {
- recursivelyProcessComponent(duplicationContext, childRef);
+ private DuplicationVisitor(DbSession session, MetricDto duplicationMetric) {
+ super(Component.Type.FILE, PRE_ORDER);
+ this.session = session;
+ this.duplicationMetric = duplicationMetric;
}
- }
- private void saveDuplications(DuplicationContext duplicationContext, BatchReport.Component component, List<BatchReport.Duplication> duplications) {
+ @Override
+ public void visitFile(Component file) {
+ visitComponent(file);
+ }
- DbComponentsRefCache.DbComponent dbComponent = dbComponentsRefCache.getByRef(component.getRef());
- String duplicationXml = createXmlDuplications(duplicationContext, dbComponent.getKey(), duplications);
- MeasureDto measureDto = new MeasureDto()
- .setMetricId(duplicationContext.metric().getId())
- .setData(duplicationXml)
- .setComponentId(dbComponent.getId())
- .setSnapshotId(component.getSnapshotId());
- dbClient.measureDao().insert(duplicationContext.session(), measureDto);
- }
+ private void visitComponent(Component component) {
+ List<BatchReport.Duplication> duplications = reportReader.readComponentDuplications(component.getRef());
+ if (!duplications.isEmpty()) {
+ BatchReport.Component batchComponent = reportReader.readComponent(component.getRef());
+ saveDuplications(batchComponent, component, duplications);
+ }
+ }
- private String createXmlDuplications(DuplicationContext duplicationContext, String componentKey, Iterable<BatchReport.Duplication> duplications) {
+ private void saveDuplications(BatchReport.Component batchComponent, Component component, List<BatchReport.Duplication> duplications) {
+ String duplicationXml = createXmlDuplications(component.getKey(), duplications);
+ MeasureDto measureDto = new MeasureDto()
+ .setMetricId(duplicationMetric.getId())
+ .setData(duplicationXml)
+ .setComponentId(dbIdsRepository.getComponentId(component))
+ .setSnapshotId(batchComponent.getSnapshotId());
+ dbClient.measureDao().insert(session, measureDto);
+ }
- StringBuilder xml = new StringBuilder();
- xml.append("<duplications>");
- for (BatchReport.Duplication duplication : duplications) {
- xml.append("<g>");
- appendDuplication(xml, componentKey, duplication.getOriginPosition());
- for (BatchReport.Duplicate duplicationBlock : duplication.getDuplicateList()) {
- processDuplicationBlock(duplicationContext, xml, duplicationBlock, componentKey);
+ private String createXmlDuplications(String componentKey, Iterable<BatchReport.Duplication> duplications) {
+ StringBuilder xml = new StringBuilder();
+ xml.append("<duplications>");
+ for (BatchReport.Duplication duplication : duplications) {
+ xml.append("<g>");
+ appendDuplication(xml, componentKey, duplication.getOriginPosition());
+ for (BatchReport.Duplicate duplicationBlock : duplication.getDuplicateList()) {
+ processDuplicationBlock(xml, duplicationBlock, componentKey);
+ }
+ xml.append("</g>");
}
- xml.append("</g>");
+ xml.append("</duplications>");
+ return xml.toString();
}
- xml.append("</duplications>");
- return xml.toString();
- }
- private void processDuplicationBlock(DuplicationContext duplicationContext, StringBuilder xml, BatchReport.Duplicate duplicate, String componentKey) {
-
- if (duplicate.hasOtherFileKey()) {
- // componentKey is only set for cross project duplications
- String crossProjectComponentKey = duplicate.getOtherFileKey();
- appendDuplication(xml, crossProjectComponentKey, duplicate);
- } else {
- if (duplicate.hasOtherFileRef()) {
- // Duplication is on a different file
- BatchReport.Component duplicationComponent = reportReader.readComponent(duplicate.getOtherFileRef());
- DbComponentsRefCache.DbComponent dbComponent = dbComponentsRefCache.getByRef(duplicationComponent.getRef());
- appendDuplication(xml, dbComponent.getKey(), duplicate);
+ private void processDuplicationBlock(StringBuilder xml, BatchReport.Duplicate duplicate, String componentKey) {
+ if (duplicate.hasOtherFileKey()) {
+ // componentKey is only set for cross project duplications
+ String crossProjectComponentKey = duplicate.getOtherFileKey();
+ appendDuplication(xml, crossProjectComponentKey, duplicate);
} else {
- // Duplication is on a the same file
- appendDuplication(xml, componentKey, duplicate);
+ if (duplicate.hasOtherFileRef()) {
+ // Duplication is on a different file
+ appendDuplication(xml, treeRootHolder.getComponentByRef(duplicate.getOtherFileRef()).getKey(), duplicate);
+ } else {
+ // Duplication is on a the same file
+ appendDuplication(xml, componentKey, duplicate);
+ }
}
}
- }
-
- private static void appendDuplication(StringBuilder xml, String componentKey, BatchReport.Duplicate duplicate) {
- appendDuplication(xml, componentKey, duplicate.getRange());
- }
-
- private static void appendDuplication(StringBuilder xml, String componentKey, Range range) {
- int length = range.getEndLine() - range.getStartLine() + 1;
- xml.append("<b s=\"").append(range.getStartLine())
- .append("\" l=\"").append(length)
- .append("\" r=\"").append(StringEscapeUtils.escapeXml(componentKey))
- .append("\"/>");
- }
-
- private static class DuplicationContext {
- private DbSession session;
- private MetricDto duplicationMetric;
-
- DuplicationContext(MetricDto duplicationMetric, DbSession session) {
- this.duplicationMetric = duplicationMetric;
- this.session = session;
- }
- public MetricDto metric() {
- return duplicationMetric;
+ private void appendDuplication(StringBuilder xml, String componentKey, BatchReport.Duplicate duplicate) {
+ appendDuplication(xml, componentKey, duplicate.getRange());
}
- public DbSession session() {
- return session;
+ private void appendDuplication(StringBuilder xml, String componentKey, Range range) {
+ int length = range.getEndLine() - range.getStartLine() + 1;
+ xml.append("<b s=\"").append(range.getStartLine())
+ .append("\" l=\"").append(length)
+ .append("\" r=\"").append(StringEscapeUtils.escapeXml(componentKey))
+ .append("\"/>");
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java
index 45c9aef8f3b..e1a6af7af2e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistEventsStep.java
@@ -28,20 +28,24 @@ import org.sonar.core.event.EventDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+
public class PersistEventsStep implements ComputationStep {
private final DbClient dbClient;
private final System2 system2;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
- public PersistEventsStep(DbClient dbClient, System2 system2, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ public PersistEventsStep(DbClient dbClient, System2 system2, TreeRootHolder treeRootHolder, BatchReportReader reportReader) {
this.dbClient = dbClient;
this.system2 = system2;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
}
@@ -49,73 +53,89 @@ public class PersistEventsStep implements ComputationStep {
public void execute() {
DbSession session = dbClient.openSession(false);
try {
- int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
- recursivelyProcessComponent(session, rootComponentRef);
+ new EventVisitor(session, reportReader.readMetadata().getAnalysisDate()).visit(treeRootHolder.getRoot());
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}
- private void recursivelyProcessComponent(DbSession session, int componentRef) {
- BatchReport.Component component = reportReader.readComponent(componentRef);
- long analysisDate = reportReader.readMetadata().getAnalysisDate();
- processEvents(session, component, analysisDate);
- saveVersionEvent(session, component, analysisDate);
+ private class EventVisitor extends DepthTraversalTypeAwareVisitor {
+
+ private final DbSession session;
+ private final long analysisDate;
- for (Integer childRef : component.getChildRefList()) {
- recursivelyProcessComponent(session, childRef);
+ private EventVisitor(DbSession session, long analysisDate) {
+ super(Component.Type.FILE, PRE_ORDER);
+ this.session = session;
+ this.analysisDate = analysisDate;
}
- }
- private void processEvents(DbSession session, BatchReport.Component component, Long analysisDate) {
- List<BatchReport.Event> events = component.getEventList();
- if (!events.isEmpty()) {
- for (BatchReport.Event event : component.getEventList()) {
- dbClient.eventDao().insert(session, newBaseEvent(component, analysisDate)
- .setName(event.getName())
- .setCategory(convertCategory(event.getCategory()))
- .setDescription(event.hasDescription() ? event.getDescription() : null)
- .setData(event.hasEventData() ? event.getEventData() : null)
- );
+ @Override
+ public void visitModule(Component module) {
+ visitProjectOrModule(module);
+ }
+
+ @Override
+ public void visitProject(Component project) {
+ visitProjectOrModule(project);
+ }
+
+ private void visitProjectOrModule(Component component) {
+ BatchReport.Component batchComponent = reportReader.readComponent(component.getRef());
+ processEvents(batchComponent, component);
+ saveVersionEvent(batchComponent, component);
+ }
+
+ private void processEvents(BatchReport.Component batchComponent, Component component) {
+ List<BatchReport.Event> events = batchComponent.getEventList();
+ if (!events.isEmpty()) {
+ for (BatchReport.Event event : events) {
+ dbClient.eventDao().insert(session, newBaseEvent(component, batchComponent.getSnapshotId())
+ .setName(event.getName())
+ .setCategory(convertCategory(event.getCategory()))
+ .setDescription(event.hasDescription() ? event.getDescription() : null)
+ .setData(event.hasEventData() ? event.getEventData() : null)
+ );
+ }
}
}
- }
- private void saveVersionEvent(DbSession session, BatchReport.Component component, Long analysisDate) {
- if (component.hasVersion()) {
- deletePreviousEventsHavingSameVersion(session, component);
- dbClient.eventDao().insert(session, newBaseEvent(component, analysisDate)
- .setName(component.getVersion())
- .setCategory(EventDto.CATEGORY_VERSION)
- );
+ private void saveVersionEvent(BatchReport.Component batchComponent, Component component) {
+ if (batchComponent.hasVersion()) {
+ deletePreviousEventsHavingSameVersion(batchComponent, component);
+ dbClient.eventDao().insert(session, newBaseEvent(component, batchComponent.getSnapshotId())
+ .setName(batchComponent.getVersion())
+ .setCategory(EventDto.CATEGORY_VERSION)
+ );
+ }
}
- }
- private void deletePreviousEventsHavingSameVersion(DbSession session, BatchReport.Component component) {
- for (EventDto dto : dbClient.eventDao().selectByComponentUuid(session, dbComponentsRefCache.getByRef(component.getRef()).getUuid())) {
- if (dto.getCategory().equals(EventDto.CATEGORY_VERSION) && dto.getName().equals(component.getVersion())) {
- dbClient.eventDao().delete(session, dto.getId());
+ private void deletePreviousEventsHavingSameVersion(BatchReport.Component batchComponent, Component component) {
+ for (EventDto dto : dbClient.eventDao().selectByComponentUuid(session, component.getUuid())) {
+ if (dto.getCategory().equals(EventDto.CATEGORY_VERSION) && dto.getName().equals(batchComponent.getVersion())) {
+ dbClient.eventDao().delete(session, dto.getId());
+ }
}
}
- }
- private EventDto newBaseEvent(BatchReport.Component component, Long analysisDate) {
- return new EventDto()
- .setComponentUuid(dbComponentsRefCache.getByRef(component.getRef()).getUuid())
- .setSnapshotId(component.getSnapshotId())
- .setCreatedAt(system2.now())
- .setDate(analysisDate);
- }
+ private EventDto newBaseEvent(Component component, long snapshotId) {
+ return new EventDto()
+ .setComponentUuid(component.getUuid())
+ .setSnapshotId(snapshotId)
+ .setCreatedAt(system2.now())
+ .setDate(analysisDate);
+ }
- private static String convertCategory(Constants.EventCategory category) {
- switch (category) {
- case ALERT:
- return EventDto.CATEGORY_ALERT;
- case PROFILE:
- return EventDto.CATEGORY_PROFILE;
- default:
- throw new IllegalArgumentException(String.format("Unsupported category %s", category.name()));
+ private String convertCategory(Constants.EventCategory category) {
+ switch (category) {
+ case ALERT:
+ return EventDto.CATEGORY_ALERT;
+ case PROFILE:
+ return EventDto.CATEGORY_PROFILE;
+ default:
+ throw new IllegalArgumentException(String.format("Unsupported category %s", category.name()));
+ }
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
index e988b39d41b..523f4a3d608 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistFileSourcesStep.java
@@ -29,14 +29,15 @@ import org.apache.commons.codec.digest.DigestUtils;
import org.apache.ibatis.session.ResultContext;
import org.apache.ibatis.session.ResultHandler;
import org.sonar.api.utils.System2;
-import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.source.db.FileSourceDto;
import org.sonar.core.source.db.FileSourceDto.Type;
import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.computation.source.ComputeFileSourceData;
import org.sonar.server.computation.source.CoverageLineReader;
import org.sonar.server.computation.source.DuplicationLineReader;
@@ -48,28 +49,48 @@ import org.sonar.server.db.DbClient;
import org.sonar.server.source.db.FileSourceDb;
import org.sonar.server.util.CloseableIterator;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
+
public class PersistFileSourcesStep implements ComputationStep {
private final DbClient dbClient;
private final System2 system2;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
- public PersistFileSourcesStep(DbClient dbClient, System2 system2, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ public PersistFileSourcesStep(DbClient dbClient, System2 system2, TreeRootHolder treeRootHolder, BatchReportReader reportReader) {
this.dbClient = dbClient;
this.system2 = system2;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
}
@Override
public void execute() {
- int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
// Don't use batch insert for file_sources since keeping all data in memory can produce OOM for big files
DbSession session = dbClient.openSession(false);
try {
- final Map<String, FileSourceDto> previousFileSourcesByUuid = new HashMap<>();
- String projectUuid = dbComponentsRefCache.getByRef(rootComponentRef).getUuid();
+ new FileSourceVisitor(session).visit(treeRootHolder.getRoot());
+ } finally {
+ MyBatis.closeQuietly(session);
+ }
+ }
+
+ private class FileSourceVisitor extends DepthTraversalTypeAwareVisitor {
+
+ private final DbSession session;
+
+ private Map<String, FileSourceDto> previousFileSourcesByUuid = new HashMap<>();
+ private String projectUuid;
+
+ private FileSourceVisitor(DbSession session) {
+ super(Component.Type.FILE, PRE_ORDER);
+ this.session = session;
+ }
+
+ @Override
+ public void visitProject(Component project) {
+ this.projectUuid = project.getUuid();
session.select("org.sonar.core.source.db.FileSourceMapper.selectHashesForProject", ImmutableMap.of("projectUuid", projectUuid, "dataType", Type.SOURCE),
new ResultHandler() {
@Override
@@ -78,90 +99,69 @@ public class PersistFileSourcesStep implements ComputationStep {
previousFileSourcesByUuid.put(dto.getFileUuid(), dto);
}
});
-
- recursivelyProcessComponent(new FileSourcesContext(session, previousFileSourcesByUuid, projectUuid), rootComponentRef);
- } finally {
- MyBatis.closeQuietly(session);
}
- }
- private void recursivelyProcessComponent(FileSourcesContext fileSourcesContext, int componentRef) {
- BatchReport.Component component = reportReader.readComponent(componentRef);
- if (component.getType().equals(Constants.ComponentType.FILE)) {
- CloseableIterator<String> linesIterator = reportReader.readFileSource(componentRef);
- LineReaders lineReaders = new LineReaders(reportReader, componentRef);
+ @Override
+ public void visitFile(Component file) {
+ int fileRef = file.getRef();
+ BatchReport.Component component = reportReader.readComponent(fileRef);
+ CloseableIterator<String> linesIterator = reportReader.readFileSource(fileRef);
+ LineReaders lineReaders = new LineReaders(reportReader, fileRef);
try {
ComputeFileSourceData computeFileSourceData = new ComputeFileSourceData(linesIterator, lineReaders.readers(), component.getLines());
ComputeFileSourceData.Data fileSourceData = computeFileSourceData.compute();
- persistSource(fileSourcesContext, fileSourceData, component);
+ persistSource(fileSourceData, file.getUuid());
} catch (Exception e) {
- throw new IllegalStateException(String.format("Cannot persist sources of %s", component.getPath()), e);
+ throw new IllegalStateException(String.format("Cannot persist sources of %s", file.getKey()), e);
} finally {
linesIterator.close();
lineReaders.close();
}
}
- for (Integer childRef : component.getChildRefList()) {
- recursivelyProcessComponent(fileSourcesContext, childRef);
- }
- }
+ private void persistSource(ComputeFileSourceData.Data fileSourceData, String componentUuid) {
+ FileSourceDb.Data fileData = fileSourceData.getFileSourceData();
- private void persistSource(FileSourcesContext fileSourcesContext, ComputeFileSourceData.Data fileSourceData, BatchReport.Component component) {
- FileSourceDb.Data fileData = fileSourceData.getFileSourceData();
-
- byte[] data = FileSourceDto.encodeSourceData(fileData);
- String dataHash = DigestUtils.md5Hex(data);
- String srcHash = fileSourceData.getSrcHash();
- String lineHashes = fileSourceData.getLineHashes();
- String componentUuid = dbComponentsRefCache.getByRef(component.getRef()).getUuid();
- FileSourceDto previousDto = fileSourcesContext.previousFileSourcesByUuid.get(componentUuid);
-
- if (previousDto == null) {
- FileSourceDto dto = new FileSourceDto()
- .setProjectUuid(fileSourcesContext.projectUuid)
- .setFileUuid(componentUuid)
- .setDataType(Type.SOURCE)
- .setBinaryData(data)
- .setSrcHash(srcHash)
- .setDataHash(dataHash)
- .setLineHashes(lineHashes)
- .setCreatedAt(system2.now())
- .setUpdatedAt(system2.now());
- dbClient.fileSourceDao().insert(fileSourcesContext.session, dto);
- fileSourcesContext.session.commit();
- } else {
- // Update only if data_hash has changed or if src_hash is missing (progressive migration)
- boolean binaryDataUpdated = !dataHash.equals(previousDto.getDataHash());
- boolean srcHashUpdated = !srcHash.equals(previousDto.getSrcHash());
- if (binaryDataUpdated || srcHashUpdated) {
- previousDto
+ byte[] data = FileSourceDto.encodeSourceData(fileData);
+ String dataHash = DigestUtils.md5Hex(data);
+ String srcHash = fileSourceData.getSrcHash();
+ String lineHashes = fileSourceData.getLineHashes();
+ FileSourceDto previousDto = previousFileSourcesByUuid.get(componentUuid);
+
+ if (previousDto == null) {
+ FileSourceDto dto = new FileSourceDto()
+ .setProjectUuid(projectUuid)
+ .setFileUuid(componentUuid)
+ .setDataType(Type.SOURCE)
.setBinaryData(data)
- .setDataHash(dataHash)
.setSrcHash(srcHash)
- .setLineHashes(lineHashes);
- // Optimization only change updated at when updating binary data to avoid unnecessary indexation by E/S
- if (binaryDataUpdated) {
- previousDto.setUpdatedAt(system2.now());
+ .setDataHash(dataHash)
+ .setLineHashes(lineHashes)
+ .setCreatedAt(system2.now())
+ .setUpdatedAt(system2.now());
+ dbClient.fileSourceDao().insert(session, dto);
+ session.commit();
+ } else {
+ // Update only if data_hash has changed or if src_hash is missing (progressive migration)
+ boolean binaryDataUpdated = !dataHash.equals(previousDto.getDataHash());
+ boolean srcHashUpdated = !srcHash.equals(previousDto.getSrcHash());
+ if (binaryDataUpdated || srcHashUpdated) {
+ previousDto
+ .setBinaryData(data)
+ .setDataHash(dataHash)
+ .setSrcHash(srcHash)
+ .setLineHashes(lineHashes);
+ // Optimization only change updated at when updating binary data to avoid unnecessary indexation by E/S
+ if (binaryDataUpdated) {
+ previousDto.setUpdatedAt(system2.now());
+ }
+ dbClient.fileSourceDao().update(previousDto);
+ session.commit();
}
- dbClient.fileSourceDao().update(previousDto);
- fileSourcesContext.session.commit();
}
}
}
- private static class FileSourcesContext {
- DbSession session;
- Map<String, FileSourceDto> previousFileSourcesByUuid;
- String projectUuid;
-
- public FileSourcesContext(DbSession session, Map<String, FileSourceDto> previousFileSourcesByUuid, String projectUuid) {
- this.previousFileSourcesByUuid = previousFileSourcesByUuid;
- this.session = session;
- this.projectUuid = projectUuid;
- }
- }
-
private static class LineReaders {
private final List<LineReader> readers = new ArrayList<>();
private final List<CloseableIterator<?>> iterators = new ArrayList<>();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java
index fb9c8287772..df107b009c2 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistIssuesStep.java
@@ -96,7 +96,7 @@ public class PersistIssuesStep implements ComputationStep {
}
}
- private void insertChanges(IssueChangeMapper mapper, DefaultIssue issue) {
+ private static void insertChanges(IssueChangeMapper mapper, DefaultIssue issue) {
for (IssueComment comment : issue.comments()) {
DefaultIssueComment c = (DefaultIssueComment) comment;
if (c.isNew()) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java
index b9e4129ff7a..f6f51d04271 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistMeasuresStep.java
@@ -29,12 +29,16 @@ import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.measure.db.MeasureDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.computation.issue.RuleCache;
import org.sonar.server.computation.measure.MetricCache;
import org.sonar.server.db.DbClient;
import static com.google.common.collect.Lists.newArrayList;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
public class PersistMeasuresStep implements ComputationStep {
@@ -46,15 +50,17 @@ public class PersistMeasuresStep implements ComputationStep {
private final DbClient dbClient;
private final RuleCache ruleCache;
private final MetricCache metricCache;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final DbIdsRepository dbIdsRepository;
+ private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
public PersistMeasuresStep(DbClient dbClient, RuleCache ruleCache, MetricCache metricCache,
- DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ DbIdsRepository dbIdsRepository, TreeRootHolder treeRootHolder, BatchReportReader reportReader) {
this.dbClient = dbClient;
this.ruleCache = ruleCache;
this.metricCache = metricCache;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.dbIdsRepository = dbIdsRepository;
+ this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
}
@@ -65,33 +71,45 @@ public class PersistMeasuresStep implements ComputationStep {
@Override
public void execute() {
- int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
- try (DbSession dbSession = dbClient.openSession(true)) {
- recursivelyProcessComponent(dbSession, rootComponentRef);
+ DbSession dbSession = dbClient.openSession(true);
+ try {
+ new MeasureVisitor(dbSession).visit(treeRootHolder.getRoot());
dbSession.commit();
+ } finally {
+ dbSession.close();
}
}
- private void recursivelyProcessComponent(DbSession dbSession, int componentRef) {
- BatchReport.Component component = reportReader.readComponent(componentRef);
- List<BatchReport.Measure> measures = reportReader.readComponentMeasures(componentRef);
- persistMeasures(dbSession, measures, component);
- for (Integer childRef : component.getChildRefList()) {
- recursivelyProcessComponent(dbSession, childRef);
+ private class MeasureVisitor extends DepthTraversalTypeAwareVisitor {
+
+ private final DbSession session;
+
+ private MeasureVisitor(DbSession session) {
+ super(Component.Type.FILE, PRE_ORDER);
+ this.session = session;
+ }
+
+ @Override
+ protected void visitAny(Component component) {
+ int componentRef = component.getRef();
+ BatchReport.Component batchComponent = reportReader.readComponent(componentRef);
+ List<BatchReport.Measure> measures = reportReader.readComponentMeasures(componentRef);
+ persistMeasures(measures, dbIdsRepository.getComponentId(component), batchComponent.getSnapshotId());
+
}
- }
- private void persistMeasures(DbSession dbSession, List<BatchReport.Measure> batchReportMeasures, final BatchReport.Component component) {
- for (BatchReport.Measure measure : batchReportMeasures) {
- if (FORBIDDEN_METRIC_KEYS.contains(measure.getMetricKey())) {
- throw new IllegalStateException(String.format("Measures on metric '%s' cannot be send in the report", measure.getMetricKey()));
+ private void persistMeasures(List<BatchReport.Measure> batchReportMeasures, long componentId, long snapshotId) {
+ for (BatchReport.Measure measure : batchReportMeasures) {
+ if (FORBIDDEN_METRIC_KEYS.contains(measure.getMetricKey())) {
+ throw new IllegalStateException(String.format("Measures on metric '%s' cannot be send in the report", measure.getMetricKey()));
+ }
+ dbClient.measureDao().insert(session, toMeasureDto(measure, componentId, snapshotId));
}
- dbClient.measureDao().insert(dbSession, toMeasureDto(measure, component));
}
}
@VisibleForTesting
- MeasureDto toMeasureDto(BatchReport.Measure in, BatchReport.Component component) {
+ MeasureDto toMeasureDto(BatchReport.Measure in, long componentId, long snapshotId) {
if (!in.hasValueType()) {
throw new IllegalStateException(String.format("Measure %s does not have value type", in));
}
@@ -109,8 +127,8 @@ public class PersistMeasuresStep implements ComputationStep {
out.setAlertText(in.hasAlertText() ? in.getAlertText() : null);
out.setDescription(in.hasDescription() ? in.getDescription() : null);
out.setSeverity(in.hasSeverity() ? in.getSeverity().name() : null);
- out.setComponentId(dbComponentsRefCache.getByRef(component.getRef()).getId());
- out.setSnapshotId(component.getSnapshotId());
+ out.setComponentId(componentId);
+ out.setSnapshotId(snapshotId);
out.setMetricId(metricCache.get(in.getMetricKey()).getId());
out.setRuleId(in.hasRuleKey() ? ruleCache.get(RuleKey.parse(in.getRuleKey())).getId() : null);
out.setCharacteristicId(in.hasCharactericId() ? in.getCharactericId() : null);
@@ -120,6 +138,13 @@ public class PersistMeasuresStep implements ComputationStep {
return out;
}
+ private MeasureDto setData(BatchReport.Measure in, MeasureDto out) {
+ if (in.hasStringValue()) {
+ out.setData(in.getStringValue());
+ }
+ return out;
+ }
+
/**
* return the numerical value as a double. It's the type used in db.
* Returns null if no numerical value found
@@ -139,12 +164,4 @@ public class PersistMeasuresStep implements ComputationStep {
return null;
}
}
-
- private MeasureDto setData(BatchReport.Measure in, MeasureDto out) {
- if (in.hasStringValue()) {
- out.setData(in.getStringValue());
- }
-
- return out;
- }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
index 8b1262c3af0..74f9bd8258e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStep.java
@@ -30,13 +30,15 @@ import org.sonar.core.measure.db.MeasureDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.computation.measure.MetricCache;
import org.sonar.server.db.DbClient;
import org.sonar.server.source.index.SourceLineIndex;
import static com.google.common.base.Objects.firstNonNull;
-import static com.google.common.base.Preconditions.checkState;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
@@ -46,18 +48,16 @@ public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
private final SourceLineIndex sourceLineIndex;
private final MetricCache metricCache;
private final System2 system;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
- private long lastCommitTimestamp = 0L;
-
public PersistNumberOfDaysSinceLastCommitStep(System2 system, DbClient dbClient, SourceLineIndex sourceLineIndex, MetricCache metricCache,
- DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ TreeRootHolder treeRootHolder, BatchReportReader reportReader) {
this.dbClient = dbClient;
this.sourceLineIndex = sourceLineIndex;
this.metricCache = metricCache;
this.system = system;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
}
@@ -68,38 +68,17 @@ public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
@Override
public void execute() {
- int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
- recursivelyProcessComponent(rootComponentRef);
+ NumberOfDaysSinceLastCommitVisitor visitor = new NumberOfDaysSinceLastCommitVisitor();
+ visitor.visit(treeRootHolder.getRoot());
- if (!commitFound()) {
- Long lastCommitFromIndex = lastCommitFromIndex(dbComponentsRefCache.getByRef(rootComponentRef).getUuid());
+ long lastCommitTimestamp = visitor.lastCommitTimestampFromReport;
+ if (lastCommitTimestamp == 0L) {
+ Long lastCommitFromIndex = lastCommitFromIndex(treeRootHolder.getRoot().getUuid());
lastCommitTimestamp = firstNonNull(lastCommitFromIndex, lastCommitTimestamp);
}
- if (commitFound()) {
- persistNumberOfDaysSinceLastCommit();
- }
- }
-
- private void recursivelyProcessComponent(int componentRef) {
- BatchReport.Component component = reportReader.readComponent(componentRef);
- BatchReport.Changesets scm = reportReader.readChangesets(componentRef);
- processScm(scm);
-
- for (Integer childRef : component.getChildRefList()) {
- recursivelyProcessComponent(childRef);
- }
- }
-
- private void processScm(@Nullable BatchReport.Changesets scm) {
- if (scm == null) {
- return;
- }
-
- for (BatchReport.Changesets.Changeset changeset : scm.getChangesetList()) {
- if (changeset.hasDate() && changeset.getDate() > lastCommitTimestamp) {
- lastCommitTimestamp = changeset.getDate();
- }
+ if (lastCommitTimestamp != 0L) {
+ persistNumberOfDaysSinceLastCommit(lastCommitTimestamp);
}
}
@@ -109,9 +88,7 @@ public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
return lastCommitDate == null ? null : lastCommitDate.getTime();
}
- private void persistNumberOfDaysSinceLastCommit() {
- checkState(commitFound(), "The last commit time should exist");
-
+ private void persistNumberOfDaysSinceLastCommit(long lastCommitTimestamp) {
long numberOfDaysSinceLastCommit = (system.now() - lastCommitTimestamp) / MILLISECONDS_PER_DAY;
DbSession dbSession = dbClient.openSession(true);
try {
@@ -125,7 +102,30 @@ public class PersistNumberOfDaysSinceLastCommitStep implements ComputationStep {
}
}
- private boolean commitFound() {
- return lastCommitTimestamp != 0L;
+ private class NumberOfDaysSinceLastCommitVisitor extends DepthTraversalTypeAwareVisitor {
+
+ private long lastCommitTimestampFromReport = 0L;
+
+ private NumberOfDaysSinceLastCommitVisitor() {
+ super(Component.Type.FILE, PRE_ORDER);
+ }
+
+ @Override
+ public void visitFile(Component component) {
+ BatchReport.Changesets scm = reportReader.readChangesets(component.getRef());
+ processScm(scm);
+ }
+
+ private void processScm(@Nullable BatchReport.Changesets scm) {
+ if (scm == null) {
+ return;
+ }
+
+ for (BatchReport.Changesets.Changeset changeset : scm.getChangesetList()) {
+ if (changeset.hasDate() && changeset.getDate() > lastCommitTimestampFromReport) {
+ lastCommitTimestampFromReport = changeset.getDate();
+ }
+ }
+ }
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java
index fa446ef3ea4..949c73698de 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistProjectLinksStep.java
@@ -35,10 +35,13 @@ import org.sonar.core.component.ComponentLinkDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
import static com.google.common.collect.Sets.newHashSet;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.PRE_ORDER;
/**
* Persist project and module links
@@ -47,7 +50,7 @@ public class PersistProjectLinksStep implements ComputationStep {
private final DbClient dbClient;
private final I18n i18n;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final TreeRootHolder treeRootHolder;
private final BatchReportReader reportReader;
private static final Map<Constants.ComponentLinkType, String> typesConverter = ImmutableMap.of(
@@ -58,10 +61,10 @@ public class PersistProjectLinksStep implements ComputationStep {
Constants.ComponentLinkType.ISSUE, ComponentLinkDto.TYPE_ISSUE_TRACKER
);
- public PersistProjectLinksStep(DbClient dbClient, I18n i18n, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader) {
+ public PersistProjectLinksStep(DbClient dbClient, I18n i18n, TreeRootHolder treeRootHolder, BatchReportReader reportReader) {
this.dbClient = dbClient;
this.i18n = i18n;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.treeRootHolder = treeRootHolder;
this.reportReader = reportReader;
}
@@ -69,65 +72,76 @@ public class PersistProjectLinksStep implements ComputationStep {
public void execute() {
DbSession session = dbClient.openSession(false);
try {
- int rootComponentRef = reportReader.readMetadata().getRootComponentRef();
- recursivelyProcessComponent(session, rootComponentRef);
+ new PorjectLinkVisitor(session).visit(treeRootHolder.getRoot());
session.commit();
} finally {
MyBatis.closeQuietly(session);
}
}
- private void recursivelyProcessComponent(DbSession session, int componentRef) {
- BatchReport.Component component = reportReader.readComponent(componentRef);
- processLinks(session, component);
+ private class PorjectLinkVisitor extends DepthTraversalTypeAwareVisitor {
- for (Integer childRef : component.getChildRefList()) {
- recursivelyProcessComponent(session, childRef);
+ private final DbSession session;
+
+ private PorjectLinkVisitor(DbSession session) {
+ super(Component.Type.FILE, PRE_ORDER);
+ this.session = session;
+ }
+
+ @Override
+ public void visitProject(Component project) {
+ processComponent(project);
}
- }
- private void processLinks(DbSession session, BatchReport.Component component) {
- if (component.getType().equals(Constants.ComponentType.PROJECT) || component.getType().equals(Constants.ComponentType.MODULE)) {
- List<BatchReport.ComponentLink> links = component.getLinkList();
- String componentUuid = dbComponentsRefCache.getByRef(component.getRef()).getUuid();
+ @Override
+ public void visitModule(Component module) {
+ processComponent(module);
+ }
+
+ private void processComponent(Component component) {
+ BatchReport.Component batchComponent = reportReader.readComponent(component.getRef());
+ processLinks(component.getUuid(), batchComponent.getLinkList());
+ }
+
+ private void processLinks(String componentUuid, List<BatchReport.ComponentLink> links) {
List<ComponentLinkDto> previousLinks = dbClient.componentLinkDao().selectByComponentUuid(session, componentUuid);
mergeLinks(session, componentUuid, links, previousLinks);
}
- }
- private void mergeLinks(DbSession session, String componentUuid, List<BatchReport.ComponentLink> links, List<ComponentLinkDto> previousLinks) {
- Set<String> linkType = newHashSet();
- for (final BatchReport.ComponentLink link : links) {
- String type = convertType(link.getType());
- if (!linkType.contains(type)) {
- linkType.add(type);
- } else {
- throw new IllegalArgumentException(String.format("Link of type '%s' has already been declared on component '%s'", type, componentUuid));
- }
+ private void mergeLinks(DbSession session, String componentUuid, List<BatchReport.ComponentLink> links, List<ComponentLinkDto> previousLinks) {
+ Set<String> linkType = newHashSet();
+ for (final BatchReport.ComponentLink link : links) {
+ String type = convertType(link.getType());
+ if (!linkType.contains(type)) {
+ linkType.add(type);
+ } else {
+ throw new IllegalArgumentException(String.format("Link of type '%s' has already been declared on component '%s'", type, componentUuid));
+ }
- ComponentLinkDto previousLink = Iterables.find(previousLinks, new Predicate<ComponentLinkDto>() {
- @Override
- public boolean apply(@Nullable ComponentLinkDto input) {
- return input != null && input.getType().equals(convertType(link.getType()));
+ ComponentLinkDto previousLink = Iterables.find(previousLinks, new Predicate<ComponentLinkDto>() {
+ @Override
+ public boolean apply(@Nullable ComponentLinkDto input) {
+ return input != null && input.getType().equals(convertType(link.getType()));
+ }
+ }, null);
+ if (previousLink == null) {
+ dbClient.componentLinkDao().insert(session,
+ new ComponentLinkDto()
+ .setComponentUuid(componentUuid)
+ .setType(type)
+ .setName(i18n.message(Locale.ENGLISH, "project_links." + type, null))
+ .setHref(link.getHref())
+ );
+ } else {
+ previousLink.setHref(link.getHref());
+ dbClient.componentLinkDao().update(session, previousLink);
}
- }, null);
- if (previousLink == null) {
- dbClient.componentLinkDao().insert(session,
- new ComponentLinkDto()
- .setComponentUuid(componentUuid)
- .setType(type)
- .setName(i18n.message(Locale.ENGLISH, "project_links." + type, null))
- .setHref(link.getHref())
- );
- } else {
- previousLink.setHref(link.getHref());
- dbClient.componentLinkDao().update(session, previousLink);
}
- }
- for (ComponentLinkDto dto : previousLinks) {
- if (!linkType.contains(dto.getType()) && ComponentLinkDto.PROVIDED_TYPES.contains(dto.getType())) {
- dbClient.componentLinkDao().delete(session, dto.getId());
+ for (ComponentLinkDto dto : previousLinks) {
+ if (!linkType.contains(dto.getType()) && ComponentLinkDto.PROVIDED_TYPES.contains(dto.getType())) {
+ dbClient.componentLinkDao().delete(session, dto.getId());
+ }
}
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java
index aee6d513529..6f7a41f3467 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PersistTestsStep.java
@@ -46,7 +46,6 @@ import org.sonar.core.source.db.FileSourceDto;
import org.sonar.core.source.db.FileSourceDto.Type;
import org.sonar.server.computation.batch.BatchReportReader;
import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DbComponentsRefCache;
import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
@@ -60,14 +59,12 @@ public class PersistTestsStep implements ComputationStep {
private final DbClient dbClient;
private final System2 system;
- private final DbComponentsRefCache dbComponentsRefCache;
private final BatchReportReader reportReader;
private final TreeRootHolder treeRootHolder;
- public PersistTestsStep(DbClient dbClient, System2 system, DbComponentsRefCache dbComponentsRefCache, BatchReportReader reportReader, TreeRootHolder treeRootHolder) {
+ public PersistTestsStep(DbClient dbClient, System2 system, BatchReportReader reportReader, TreeRootHolder treeRootHolder) {
this.dbClient = dbClient;
this.system = system;
- this.dbComponentsRefCache = dbComponentsRefCache;
this.reportReader = reportReader;
this.treeRootHolder = treeRootHolder;
}
@@ -76,12 +73,11 @@ public class PersistTestsStep implements ComputationStep {
public void execute() {
DbSession session = dbClient.openSession(true);
try {
- TestDepthTraversalTypeAwareVisitor visitor = new TestDepthTraversalTypeAwareVisitor(session, dbComponentsRefCache);
+ TestDepthTraversalTypeAwareVisitor visitor = new TestDepthTraversalTypeAwareVisitor(session);
visitor.visit(treeRootHolder.getRoot());
session.commit();
if (visitor.hasUnprocessedCoverageDetails) {
- String projectKey = dbComponentsRefCache.getByRef(reportReader.readMetadata().getRootComponentRef()).getKey();
- LOG.warn("Some coverage tests are not taken into account during analysis of project '{}'", projectKey);
+ LOG.warn("Some coverage tests are not taken into account during analysis of project '{}'", visitor.getProjectKey());
}
} finally {
MyBatis.closeQuietly(session);
@@ -95,17 +91,17 @@ public class PersistTestsStep implements ComputationStep {
private class TestDepthTraversalTypeAwareVisitor extends DepthTraversalTypeAwareVisitor {
final DbSession session;
- final DbComponentsRefCache dbComponentsRefCache;
final Map<String, FileSourceDto> existingFileSourcesByUuid;
final String projectUuid;
+ final String projectKey;
boolean hasUnprocessedCoverageDetails = false;
- public TestDepthTraversalTypeAwareVisitor(DbSession session, DbComponentsRefCache dbComponentsRefCache) {
+ public TestDepthTraversalTypeAwareVisitor(DbSession session) {
super(Component.Type.FILE, Order.PRE_ORDER);
this.session = session;
- this.dbComponentsRefCache = dbComponentsRefCache;
this.existingFileSourcesByUuid = new HashMap<>();
this.projectUuid = treeRootHolder.getRoot().getUuid();
+ this.projectKey = treeRootHolder.getRoot().getKey();
session.select("org.sonar.core.source.db.FileSourceMapper.selectHashesForProject",
ImmutableMap.of("projectUuid", treeRootHolder.getRoot().getUuid(), "dataType", Type.TEST),
new ResultHandler() {
@@ -164,11 +160,11 @@ public class PersistTestsStep implements ComputationStep {
BatchReport.Component component) {
Set<String> unprocessedCoverageDetailNames = new HashSet<>(coveredFilesByName.rowKeySet());
unprocessedCoverageDetailNames.removeAll(testsByName.keySet());
- boolean hasUnprocessedCoverageDetails = !unprocessedCoverageDetailNames.isEmpty();
- if (hasUnprocessedCoverageDetails) {
+ boolean hasUnprocessedCoverage = !unprocessedCoverageDetailNames.isEmpty();
+ if (hasUnprocessedCoverage) {
LOG.trace("The following test coverages for file '{}' have not been taken into account: {}", component.getPath(), Joiner.on(", ").join(unprocessedCoverageDetailNames));
}
- return hasUnprocessedCoverageDetails;
+ return hasUnprocessedCoverage;
}
private List<FileSourceDb.Test> addCoveredFilesToTests(Multimap<String, FileSourceDb.Test.Builder> testsByName,
@@ -247,7 +243,11 @@ public class PersistTestsStep implements ComputationStep {
}
private String getUuid(int fileRef) {
- return dbComponentsRefCache.getByRef(fileRef).getUuid();
+ return treeRootHolder.getComponentByRef(fileRef).getUuid();
+ }
+
+ public String getProjectKey() {
+ return projectKey;
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PopulateComponentsUuidAndKeyStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PopulateComponentsUuidAndKeyStep.java
index 84d521f6fe3..7c17fe3488b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PopulateComponentsUuidAndKeyStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PopulateComponentsUuidAndKeyStep.java
@@ -115,7 +115,7 @@ public class PopulateComponentsUuidAndKeyStep implements ComputationStep {
feedComponent((ComponentImpl) component, componentKey, componentContext.componentUuidsByKey);
}
- private void feedComponent(ComponentImpl component, String componentKey, Map<String, String> componentUuidByKey) {
+ private static void feedComponent(ComponentImpl component, String componentKey, Map<String, String> componentUuidByKey) {
component.setKey(componentKey);
String componentUuid = componentUuidByKey.get(componentKey);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeDatastoresStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeDatastoresStep.java
index b5928672a23..9dddd4cf078 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeDatastoresStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/PurgeDatastoresStep.java
@@ -24,33 +24,35 @@ import org.sonar.core.computation.dbcleaner.ProjectCleaner;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.core.purge.IdUuidPair;
-import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
import org.sonar.server.computation.component.ProjectSettingsRepository;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.db.DbClient;
public class PurgeDatastoresStep implements ComputationStep {
private final ProjectCleaner projectCleaner;
private final DbClient dbClient;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final DbIdsRepository dbIdsRepository;
+ private final TreeRootHolder treeRootHolder;
private final ProjectSettingsRepository projectSettingsRepository;
- private final BatchReportReader reportReader;
- public PurgeDatastoresStep(DbClient dbClient, ProjectCleaner projectCleaner, DbComponentsRefCache dbComponentsRefCache, ProjectSettingsRepository projectSettingsRepository, BatchReportReader reportReader) {
+ public PurgeDatastoresStep(DbClient dbClient, ProjectCleaner projectCleaner, DbIdsRepository dbIdsRepository, TreeRootHolder treeRootHolder,
+ ProjectSettingsRepository projectSettingsRepository) {
this.projectCleaner = projectCleaner;
this.dbClient = dbClient;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.dbIdsRepository = dbIdsRepository;
+ this.treeRootHolder = treeRootHolder;
this.projectSettingsRepository = projectSettingsRepository;
- this.reportReader = reportReader;
}
@Override
public void execute() {
DbSession session = dbClient.openSession(true);
try {
- DbComponentsRefCache.DbComponent project = dbComponentsRefCache.getByRef(reportReader.readMetadata().getRootComponentRef());
- projectCleaner.purge(session, new IdUuidPair(project.getId(), project.getUuid()), projectSettingsRepository.getProjectSettings(project.getKey()));
+ Component project = treeRootHolder.getRoot();
+ projectCleaner.purge(session, new IdUuidPair(dbIdsRepository.getComponentId(project), project.getUuid()), projectSettingsRepository.getProjectSettings(project.getKey()));
session.commit();
} finally {
MyBatis.closeQuietly(session);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
index 6064899b711..3a7c955b556 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/QualityProfileEventsStep.java
@@ -21,6 +21,7 @@ package org.sonar.server.computation.step;
import com.google.common.base.Optional;
import com.google.common.collect.ImmutableSortedMap;
+import java.util.Collections;
import java.util.Date;
import java.util.Map;
import javax.annotation.Nullable;
@@ -75,17 +76,25 @@ public class QualityProfileEventsStep implements ComputationStep {
}
// Load current profiles
- Map<String, QualityProfile> previousProfiles = QPMeasureData.fromJson(previousMeasure.get().getData()).getProfilesByKey();
Optional<BatchReport.Measure> currentMeasure = measureRepository.findCurrent(projectComponent, CoreMetrics.QUALITY_PROFILES);
if (!currentMeasure.isPresent()) {
throw new IllegalStateException("Missing measure " + CoreMetrics.QUALITY_PROFILES + " for component " + projectComponent.getRef());
}
Map<String, QualityProfile> currentProfiles = QPMeasureData.fromJson(currentMeasure.get().getStringValue()).getProfilesByKey();
+ Map<String, QualityProfile> previousProfiles = parseJsonData(previousMeasure);
detectNewOrUpdatedProfiles(projectComponent, previousProfiles, currentProfiles);
detectNoMoreUsedProfiles(projectComponent, previousProfiles, currentProfiles);
}
+ private static Map<String, QualityProfile> parseJsonData(Optional<MeasureDto> previousMeasure) {
+ String data = previousMeasure.get().getData();
+ if (data == null) {
+ return Collections.emptyMap();
+ }
+ return QPMeasureData.fromJson(data).getProfilesByKey();
+ }
+
private void detectNoMoreUsedProfiles(Component context, Map<String, QualityProfile> previousProfiles, Map<String, QualityProfile> currentProfiles) {
for (QualityProfile previousProfile : previousProfiles.values()) {
if (!currentProfiles.containsKey(previousProfile.getQpKey())) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java
index f5ec9173f2f..cbc929306ea 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/SendIssueNotificationsStep.java
@@ -25,8 +25,8 @@ import java.util.Map;
import java.util.Set;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.server.computation.batch.BatchReportReader;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.DbComponentsRefCache.DbComponent;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.TreeRootHolder;
import org.sonar.server.computation.issue.IssueCache;
import org.sonar.server.computation.issue.RuleCache;
import org.sonar.server.issue.notification.IssueChangeNotification;
@@ -50,16 +50,16 @@ public class SendIssueNotificationsStep implements ComputationStep {
private final IssueCache issueCache;
private final RuleCache rules;
- private final DbComponentsRefCache dbComponentsRefCache;
+ private final TreeRootHolder treeRootHolder;
private final NotificationService service;
private final BatchReportReader reportReader;
private NewIssuesNotificationFactory newIssuesNotificationFactory;
- public SendIssueNotificationsStep(IssueCache issueCache, RuleCache rules, DbComponentsRefCache dbComponentsRefCache, NotificationService service,
+ public SendIssueNotificationsStep(IssueCache issueCache, RuleCache rules, TreeRootHolder treeRootHolder, NotificationService service,
BatchReportReader reportReader, NewIssuesNotificationFactory newIssuesNotificationFactory) {
this.issueCache = issueCache;
this.rules = rules;
- this.dbComponentsRefCache = dbComponentsRefCache;
+ this.treeRootHolder = treeRootHolder;
this.service = service;
this.reportReader = reportReader;
this.newIssuesNotificationFactory = newIssuesNotificationFactory;
@@ -67,13 +67,13 @@ public class SendIssueNotificationsStep implements ComputationStep {
@Override
public void execute() {
- DbComponent project = dbComponentsRefCache.getByRef(reportReader.readMetadata().getRootComponentRef());
+ Component project = treeRootHolder.getRoot();
if (service.hasProjectSubscribersForTypes(project.getUuid(), NOTIF_TYPES)) {
doExecute(project);
}
}
- private void doExecute(DbComponent project) {
+ private void doExecute(Component project) {
NewIssuesStatistics newIssuesStats = new NewIssuesStatistics();
CloseableIterator<DefaultIssue> issues = issueCache.traverse();
String projectName = reportReader.readComponent(reportReader.readMetadata().getRootComponentRef()).getName();
@@ -97,7 +97,7 @@ public class SendIssueNotificationsStep implements ComputationStep {
sendNewIssuesStatistics(newIssuesStats, project, projectName);
}
- private void sendNewIssuesStatistics(NewIssuesStatistics statistics, DbComponent project, String projectName) {
+ private void sendNewIssuesStatistics(NewIssuesStatistics statistics, Component project, String projectName) {
if (statistics.hasIssues()) {
NewIssuesStatistics.Stats globalStatistics = statistics.globalStatistics();
long analysisDate = reportReader.readMetadata().getAnalysisDate();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
index 53c19ad76b7..7fda85767cd 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/computation/step/ValidateProjectStep.java
@@ -78,7 +78,8 @@ public class ValidateProjectStep implements ComputationStep {
return input.key();
}
});
- ValidateProjectsVisitor visitor = new ValidateProjectsVisitor(session, dbClient.componentDao(), settings.getBoolean(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION), modulesByKey);
+ ValidateProjectsVisitor visitor = new ValidateProjectsVisitor(session, dbClient.componentDao(),
+ settings.getBoolean(CoreProperties.CORE_PREVENT_AUTOMATIC_PROJECT_CREATION), modulesByKey);
visitor.visit(treeRootHolder.getRoot());
if (!visitor.validationMessages.isEmpty()) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java b/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java
index 40d8a4f3201..d1cfe313845 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/config/ws/PropertiesWs.java
@@ -36,7 +36,7 @@ public class PropertiesWs implements WebService {
controller.done();
}
- private void defineIndexAction(NewController controller) {
+ private static void defineIndexAction(NewController controller) {
controller.createAction("index")
.setDescription("Documentation of this web service is available <a href=\"http://redirect.sonarsource.com/doc/old-web-service-api.html\">here</a>")
.setSince("2.6")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/dashboard/template/ProjectTimeMachineDashboard.java b/server/sonar-server/src/main/java/org/sonar/server/dashboard/template/ProjectTimeMachineDashboard.java
index f34b456cb94..13c85036c1d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/dashboard/template/ProjectTimeMachineDashboard.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/dashboard/template/ProjectTimeMachineDashboard.java
@@ -55,7 +55,7 @@ public final class ProjectTimeMachineDashboard extends DashboardTemplate {
return dashboard;
}
- private void addFirstColumn(Dashboard dashboard) {
+ private static void addFirstColumn(Dashboard dashboard) {
Widget timelineWidget = dashboard.addWidget("timeline", 1);
timelineWidget.setProperty(METRIC1, CoreMetrics.COMPLEXITY_KEY);
timelineWidget.setProperty(METRIC2, CoreMetrics.TECHNICAL_DEBT_KEY);
@@ -83,7 +83,7 @@ public final class ProjectTimeMachineDashboard extends DashboardTemplate {
duplicationTimeMachineWidget.setProperty(METRIC4, CoreMetrics.DUPLICATED_FILES_KEY);
}
- private void addSecondColumn(Dashboard dashboard) {
+ private static void addSecondColumn(Dashboard dashboard) {
Widget rulesTimeMachineWidget = addTimeMachineWidgetOnSecondColumn(dashboard);
rulesTimeMachineWidget.setProperty(METRIC1, CoreMetrics.VIOLATIONS_KEY);
rulesTimeMachineWidget.setProperty(METRIC2, CoreMetrics.BLOCKER_VIOLATIONS_KEY);
@@ -110,15 +110,15 @@ public final class ProjectTimeMachineDashboard extends DashboardTemplate {
testsTimeMachineWidget.setProperty(METRIC8, CoreMetrics.TEST_EXECUTION_TIME_KEY);
}
- private Widget addTimeMachineWidgetOnFirstColumn(Dashboard dashboard) {
+ private static Widget addTimeMachineWidgetOnFirstColumn(Dashboard dashboard) {
return addTimeMachineWidget(dashboard, 1);
}
- private Widget addTimeMachineWidgetOnSecondColumn(Dashboard dashboard) {
+ private static Widget addTimeMachineWidgetOnSecondColumn(Dashboard dashboard) {
return addTimeMachineWidget(dashboard, 2);
}
- private Widget addTimeMachineWidget(Dashboard dashboard, int columnIndex) {
+ private static Widget addTimeMachineWidget(Dashboard dashboard, int columnIndex) {
Widget widget = dashboard.addWidget("time_machine", columnIndex);
widget.setProperty("displaySparkLine", "true");
return widget;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/MigrationStepModule.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/MigrationStepModule.java
index cde817e8024..a6371738726 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/MigrationStepModule.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/MigrationStepModule.java
@@ -70,6 +70,7 @@ import org.sonar.server.db.migrations.v52.DropDependenciesComponentColumns;
import org.sonar.server.db.migrations.v52.FeedDependenciesComponentUuids;
import org.sonar.server.db.migrations.v52.FeedEventsComponentUuid;
import org.sonar.server.db.migrations.v52.FeedFileSourcesDataType;
+import org.sonar.server.db.migrations.v52.FeedMetricsBooleans;
import org.sonar.server.db.migrations.v52.FeedProjectLinksComponentUuid;
import org.sonar.server.db.migrations.v52.MoveProjectProfileAssociation;
@@ -144,6 +145,7 @@ public class MigrationStepModule extends Module {
FeedDependenciesComponentUuids.class,
DropDependenciesComponentColumns.class,
FeedFileSourcesDataType.class,
+ FeedMetricsBooleans.class,
AddDependenciesColumns.class);
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/ReplaceIssueFiltersProjectKeyByUuid.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/ReplaceIssueFiltersProjectKeyByUuid.java
index 0beb52287df..849447578a6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/ReplaceIssueFiltersProjectKeyByUuid.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v50/ReplaceIssueFiltersProjectKeyByUuid.java
@@ -25,9 +25,7 @@ import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Date;
-
import javax.annotation.Nullable;
-
import org.apache.commons.dbutils.DbUtils;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.Database;
@@ -103,7 +101,7 @@ public class ReplaceIssueFiltersProjectKeyByUuid extends BaseDataChange {
return newFields.toString();
}
- private void append(PreparedStatement pstmt, StringBuilder newFields, @Nullable String projectKey) throws SQLException {
+ private static void append(PreparedStatement pstmt, StringBuilder newFields, @Nullable String projectKey) throws SQLException {
if (projectKey != null) {
pstmt.setString(1, projectKey);
ResultSet rs = null;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/AddNewCharacteristics.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/AddNewCharacteristics.java
index 395ff13cc37..6c885e1e5f6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/AddNewCharacteristics.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v51/AddNewCharacteristics.java
@@ -19,13 +19,13 @@
*/
package org.sonar.server.db.migrations.v51;
+import com.google.common.base.Predicate;
+import com.google.common.collect.Iterables;
import java.sql.SQLException;
import java.util.Date;
import java.util.List;
-
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.utils.MessageException;
@@ -34,9 +34,6 @@ import org.sonar.core.persistence.Database;
import org.sonar.server.db.migrations.BaseDataChange;
import org.sonar.server.db.migrations.Select;
-import com.google.common.base.Predicate;
-import com.google.common.collect.Iterables;
-
/**
* See http://jira.sonarsource.com/browse/SONAR-6187
*
@@ -97,7 +94,7 @@ public class AddNewCharacteristics extends BaseDataChange {
*
* If the characteristic 'Usability' is already at the right place, nothing will be done.
*/
- private int moveCharacteristicsDownToBeAbleToInsertUsability(CharacteristicsContext characteristicsContext) throws SQLException {
+ private static int moveCharacteristicsDownToBeAbleToInsertUsability(CharacteristicsContext characteristicsContext) throws SQLException {
Characteristic security = characteristicsContext.findCharacteristicByKey(SECURITY_KEY);
Characteristic usability = characteristicsContext.findCharacteristicByKey(USABILITY_KEY);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleans.java b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleans.java
new file mode 100644
index 00000000000..bb97aa65a94
--- /dev/null
+++ b/server/sonar-server/src/main/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleans.java
@@ -0,0 +1,43 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v52;
+
+import java.sql.SQLException;
+import org.sonar.core.persistence.Database;
+import org.sonar.server.db.migrations.BaseDataChange;
+
+public class FeedMetricsBooleans extends BaseDataChange {
+
+ public FeedMetricsBooleans(Database db) {
+ super(db);
+ }
+
+ @Override
+ public void execute(Context context) throws SQLException {
+ context.prepareUpsert("update metrics set optimized_best_value=?, hidden=?, delete_historical_data=? " +
+ "where user_managed=? or optimized_best_value is null or hidden is null or delete_historical_data is null")
+ .setBoolean(1, false)
+ .setBoolean(2, false)
+ .setBoolean(3, false)
+ .setBoolean(4, true)
+ .execute().commit();
+ }
+}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtCharacteristicsXMLImporter.java b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtCharacteristicsXMLImporter.java
index d48de3632f3..34848604a87 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtCharacteristicsXMLImporter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtCharacteristicsXMLImporter.java
@@ -20,6 +20,12 @@
package org.sonar.server.debt;
+import java.io.Reader;
+import java.io.StringReader;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
import org.apache.commons.lang.StringUtils;
import org.codehaus.stax2.XMLInputFactory2;
import org.codehaus.staxmate.SMInputFactory;
@@ -30,14 +36,6 @@ import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
import org.sonar.api.server.rule.RulesDefinition;
import org.sonar.server.debt.DebtModelXMLExporter.DebtModel;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-
import static org.sonar.server.debt.DebtModelXMLExporter.CHARACTERISTIC;
import static org.sonar.server.debt.DebtModelXMLExporter.CHARACTERISTIC_KEY;
import static org.sonar.server.debt.DebtModelXMLExporter.CHARACTERISTIC_NAME;
@@ -74,7 +72,7 @@ public class DebtCharacteristicsXMLImporter {
return debtModel;
}
- private SMInputFactory initStax() {
+ private static SMInputFactory initStax() {
XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java
index b9d79cf1ebd..6156e38e636 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelOperations.java
@@ -22,6 +22,10 @@ package org.sonar.server.debt;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import java.util.Date;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.ibatis.session.SqlSession;
import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtCharacteristic;
@@ -38,12 +42,6 @@ import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;
import org.sonar.server.util.Validation;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Date;
-import java.util.List;
-
@ServerSide
public class DebtModelOperations {
@@ -150,7 +148,7 @@ public class DebtModelOperations {
}
}
- private int getOrder(CharacteristicDto characteristicDto) {
+ private static int getOrder(CharacteristicDto characteristicDto) {
Integer order = characteristicDto.getOrder();
if (order == null) {
throw new IllegalArgumentException(String.format("The order of the characteristic '%s' should not be null", characteristicDto.getKey()));
diff --git a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelXMLExporter.java b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelXMLExporter.java
index 428983b2de6..be554876a30 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelXMLExporter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtModelXMLExporter.java
@@ -24,14 +24,13 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Multimap;
import com.google.common.collect.Ordering;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ServerSide;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.server.debt.DebtCharacteristic;
-import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
-import org.xml.sax.InputSource;
-
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import java.util.List;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.xml.transform.OutputKeys;
@@ -41,14 +40,13 @@ import javax.xml.transform.TransformerException;
import javax.xml.transform.sax.SAXSource;
import javax.xml.transform.sax.SAXTransformerFactory;
import javax.xml.transform.stream.StreamResult;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.nio.charset.StandardCharsets;
-import java.util.Collections;
-import java.util.List;
-import java.util.regex.Matcher;
-import java.util.regex.Pattern;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ServerSide;
+import org.sonar.api.server.debt.DebtCharacteristic;
+import org.sonar.api.server.debt.internal.DefaultDebtCharacteristic;
+import org.xml.sax.InputSource;
import static com.google.common.collect.Lists.newArrayList;
@@ -147,7 +145,7 @@ public class DebtModelXMLExporter {
return result;
}
- private void processProperty(String key, @Nullable String val, String text, StringBuilder xml) {
+ private static void processProperty(String key, @Nullable String val, String text, StringBuilder xml) {
xml.append("<" + PROPERTY + "><" + PROPERTY_KEY + ">");
xml.append(StringEscapeUtils.escapeXml(key));
xml.append("</" + PROPERTY_KEY + ">");
@@ -164,7 +162,7 @@ public class DebtModelXMLExporter {
xml.append("</" + PROPERTY + ">");
}
- private String prettyFormatXml(String xml) {
+ private static String prettyFormatXml(String xml) {
try {
Transformer serializer = SAXTransformerFactory.newInstance().newTransformer();
serializer.setOutputProperty(OutputKeys.INDENT, "yes");
@@ -240,7 +238,7 @@ public class DebtModelXMLExporter {
});
}
- private List<DebtCharacteristic> sortByOrder(List<DebtCharacteristic> characteristics) {
+ private static List<DebtCharacteristic> sortByOrder(List<DebtCharacteristic> characteristics) {
Collections.sort(characteristics, new Ordering<DebtCharacteristic>() {
@Override
public int compare(@Nullable DebtCharacteristic left, @Nullable DebtCharacteristic right) {
@@ -253,7 +251,7 @@ public class DebtModelXMLExporter {
return characteristics;
}
- private List<DebtCharacteristic> sortByName(List<DebtCharacteristic> characteristics) {
+ private static List<DebtCharacteristic> sortByName(List<DebtCharacteristic> characteristics) {
Collections.sort(characteristics, new Ordering<DebtCharacteristic>() {
@Override
public int compare(@Nullable DebtCharacteristic left, @Nullable DebtCharacteristic right) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java
index 7b30834dfd9..2f119bc0e13 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/debt/DebtRulesXMLImporter.java
@@ -23,28 +23,26 @@ package org.sonar.server.debt;
import com.google.common.base.Predicate;
import com.google.common.base.Strings;
import com.google.common.collect.Iterables;
+import java.io.Reader;
+import java.io.StringReader;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.math.NumberUtils;
import org.codehaus.stax2.XMLInputFactory2;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.utils.Duration;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.server.debt.DebtModelXMLExporter.RuleDebt;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.StringReader;
-import java.util.List;
-
import static com.google.common.collect.Lists.newArrayList;
import static org.sonar.server.debt.DebtModelXMLExporter.CHARACTERISTIC;
import static org.sonar.server.debt.DebtModelXMLExporter.CHARACTERISTIC_KEY;
@@ -88,7 +86,7 @@ public class DebtRulesXMLImporter {
return ruleDebts;
}
- private SMInputFactory initStax() {
+ private static SMInputFactory initStax() {
XMLInputFactory xmlFactory = XMLInputFactory2.newInstance();
xmlFactory.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
xmlFactory.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.FALSE);
@@ -141,7 +139,7 @@ public class DebtRulesXMLImporter {
return null;
}
- private Property processProperty(ValidationMessages validationMessages, SMInputCursor cursor) throws XMLStreamException {
+ private static Property processProperty(ValidationMessages validationMessages, SMInputCursor cursor) throws XMLStreamException {
SMInputCursor c = cursor.childElementCursor();
String key = null;
int value = 0;
@@ -183,7 +181,7 @@ public class DebtRulesXMLImporter {
}
@CheckForNull
- private RuleDebt createRuleDebt(RuleKey ruleKey, String function, @Nullable String coefficient, @Nullable String offset, ValidationMessages validationMessages) {
+ private static RuleDebt createRuleDebt(RuleKey ruleKey, String function, @Nullable String coefficient, @Nullable String offset, ValidationMessages validationMessages) {
if ("linear_threshold".equals(function) && coefficient != null) {
validationMessages.addWarningText(String.format("Linear with threshold function is no longer used, remediation function of '%s' is replaced by linear.", ruleKey));
return new RuleDebt().setRuleKey(ruleKey).setFunction(DebtRemediationFunction.Type.LINEAR.name()).setCoefficient(coefficient);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsJsonWriter.java b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsJsonWriter.java
index cddf4b3ed6d..e5ddea9269b 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsJsonWriter.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/duplication/ws/DuplicationsJsonWriter.java
@@ -21,17 +21,15 @@
package org.sonar.server.duplication.ws;
import com.google.common.annotations.VisibleForTesting;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.Nullable;
import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.server.component.db.ComponentDao;
-import javax.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
-
import static com.google.common.collect.Maps.newHashMap;
@ServerSide
@@ -65,7 +63,7 @@ public class DuplicationsJsonWriter {
}
}
- private void writeDuplication(Map<String, String> refByComponentKey, DuplicationsParser.Duplication duplication, JsonWriter json) {
+ private static void writeDuplication(Map<String, String> refByComponentKey, DuplicationsParser.Duplication duplication, JsonWriter json) {
String ref = null;
ComponentDto componentDto = duplication.file();
if (componentDto != null) {
@@ -104,13 +102,13 @@ public class DuplicationsJsonWriter {
}
}
- private void addFile(JsonWriter json, ComponentDto file) {
+ private static void addFile(JsonWriter json, ComponentDto file) {
json.prop("key", file.key());
json.prop("uuid", file.uuid());
json.prop("name", file.longName());
}
- private void addProject(JsonWriter json, @Nullable ComponentDto project, @Nullable ComponentDto subProject) {
+ private static void addProject(JsonWriter json, @Nullable ComponentDto project, @Nullable ComponentDto subProject) {
if (project != null) {
json.prop("project", project.key());
json.prop("projectUuid", project.uuid());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/es/request/ProxySearchRequestBuilder.java b/server/sonar-server/src/main/java/org/sonar/server/es/request/ProxySearchRequestBuilder.java
index 2a000de2ea0..33473039147 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/es/request/ProxySearchRequestBuilder.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/es/request/ProxySearchRequestBuilder.java
@@ -20,6 +20,8 @@
package org.sonar.server.es.request;
+import java.io.IOException;
+import java.util.Arrays;
import org.elasticsearch.action.ListenableActionFuture;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
@@ -31,9 +33,6 @@ import org.elasticsearch.common.xcontent.XContentFactory;
import org.sonar.api.utils.log.Profiler;
import org.sonar.server.es.EsClient;
-import java.io.IOException;
-import java.util.Arrays;
-
public class ProxySearchRequestBuilder extends SearchRequestBuilder {
public ProxySearchRequestBuilder(Client client) {
@@ -82,7 +81,7 @@ public class ProxySearchRequestBuilder extends SearchRequestBuilder {
return message.toString();
}
- private String xContentToString(ToXContent toXContent) {
+ private static String xContentToString(ToXContent toXContent) {
try {
XContentBuilder builder = XContentFactory.jsonBuilder();
toXContent.toXContent(builder, ToXContent.EMPTY_PARAMS);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
index 1894564147d..83356b5a1c1 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/CommentAction.java
@@ -21,15 +21,14 @@
package org.sonar.server.issue;
import com.google.common.base.Strings;
-import org.sonar.api.server.ServerSide;
+import java.util.Collection;
+import java.util.Map;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.server.ServerSide;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
-import java.util.Collection;
-import java.util.Map;
-
@ServerSide
public class CommentAction extends Action {
@@ -55,7 +54,7 @@ public class CommentAction extends Action {
return true;
}
- private String comment(Map<String, Object> properties) {
+ private static String comment(Map<String, Object> properties) {
String param = (String) properties.get(COMMENT_PROPERTY);
if (Strings.isNullOrEmpty(param)) {
throw new IllegalArgumentException("Missing parameter : '" + COMMENT_PROPERTY + "'");
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
index 83db935db6a..69fbceaf448 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/InternalRubyIssueService.java
@@ -26,8 +26,13 @@ import com.google.common.base.Strings;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.issue.ActionPlan;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.IssueComment;
@@ -36,6 +41,7 @@ import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.DefaultIssueComment;
import org.sonar.api.issue.internal.FieldDiffs;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.SonarException;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.ActionPlanStats;
@@ -55,14 +61,6 @@ import org.sonar.server.user.UserSession;
import org.sonar.server.util.RubyUtils;
import org.sonar.server.util.Validation;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-import java.util.Map;
-
import static com.google.common.collect.Lists.newArrayList;
/**
@@ -385,7 +383,7 @@ public class InternalRubyIssueService {
}
}
- private Date checkAndReturnDeadline(String deadLineParam, Result<ActionPlan> result) {
+ private static Date checkAndReturnDeadline(String deadLineParam, Result<ActionPlan> result) {
Date deadLine = null;
if (!Strings.isNullOrEmpty(deadLineParam)) {
try {
@@ -492,7 +490,7 @@ public class InternalRubyIssueService {
return execute(props);
}
- private void overrideProps(Map<String, Object> props, Map<String, Object> overrideProps) {
+ private static void overrideProps(Map<String, Object> props, Map<String, Object> overrideProps) {
for (Map.Entry<String, Object> entry : overrideProps.entrySet()) {
props.put(entry.getKey(), entry.getValue());
}
@@ -609,32 +607,32 @@ public class InternalRubyIssueService {
return issueBulkChangeService.execute(issueBulkChangeQuery, userSession);
}
- private void checkMandatoryParameter(String value, String paramName, Result result) {
+ private static void checkMandatoryParameter(String value, String paramName, Result result) {
if (Strings.isNullOrEmpty(value)) {
result.addError(Result.Message.ofL10n(Validation.CANT_BE_EMPTY_MESSAGE, paramName));
}
}
- private void checkMandatorySizeParameter(String value, String paramName, Integer size, Result result) {
+ private static void checkMandatorySizeParameter(String value, String paramName, Integer size, Result result) {
checkMandatoryParameter(value, paramName, result);
if (!Strings.isNullOrEmpty(value) && value.length() > size) {
result.addError(Result.Message.ofL10n(Validation.IS_TOO_LONG_MESSAGE, paramName, size));
}
}
- private void checkOptionalSizeParameter(String value, String paramName, Integer size, Result result) {
+ private static void checkOptionalSizeParameter(String value, String paramName, Integer size, Result result) {
if (!Strings.isNullOrEmpty(value) && value.length() > size) {
result.addError(Result.Message.ofL10n(Validation.IS_TOO_LONG_MESSAGE, paramName, size));
}
}
- private void checkOptionalSizeParameter(String value, String paramName, Integer size) {
+ private static void checkOptionalSizeParameter(String value, String paramName, Integer size) {
if (!Strings.isNullOrEmpty(value) && value.length() > size) {
throw new BadRequestException(Validation.IS_TOO_LONG_MESSAGE, paramName, size);
}
}
- public int maxPageSize() {
+ public static int maxPageSize() {
return QueryContext.MAX_LIMIT;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
index 768a274f59c..29f84cafcca 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/IssueBulkChangeService.java
@@ -25,10 +25,18 @@ import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.IssueChangeContext;
-import org.sonar.core.notification.NotificationManager;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rules.Rule;
import org.sonar.api.utils.log.Logger;
@@ -36,6 +44,7 @@ import org.sonar.api.utils.log.Loggers;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.issue.db.IssueDto;
import org.sonar.core.issue.db.IssueStorage;
+import org.sonar.core.notification.NotificationManager;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.MyBatis;
import org.sonar.server.db.DbClient;
@@ -46,17 +55,6 @@ import org.sonar.server.issue.notification.IssueChangeNotification;
import org.sonar.server.rule.DefaultRuleFinder;
import org.sonar.server.user.UserSession;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
import static com.google.common.collect.Sets.newHashSet;
@@ -167,7 +165,7 @@ public class IssueBulkChangeService {
return bulkActions;
}
- private void applyAction(Action action, ActionContext actionContext, IssueBulkChangeQuery issueBulkChangeQuery, IssueBulkChangeResult result) {
+ private static void applyAction(Action action, ActionContext actionContext, IssueBulkChangeQuery issueBulkChangeQuery, IssueBulkChangeResult result) {
Issue issue = actionContext.issue();
try {
if (action.supports(issue) && action.execute(issueBulkChangeQuery.properties(action.key()), actionContext)) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
index 74e252e36a4..174f943f7cd 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/SetSeverityAction.java
@@ -20,20 +20,18 @@
package org.sonar.server.issue;
+import com.google.common.base.Strings;
import java.util.Collection;
import java.util.Map;
-
-import org.sonar.api.server.ServerSide;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.condition.Condition;
import org.sonar.api.issue.condition.IsUnResolved;
import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.IssueUpdater;
import org.sonar.server.user.UserSession;
-import com.google.common.base.Strings;
-
@ServerSide
public class SetSeverityAction extends Action {
@@ -69,7 +67,7 @@ public class SetSeverityAction extends Action {
return issueUpdater.setManualSeverity((DefaultIssue) context.issue(), severity(properties), context.issueChangeContext());
}
- private String severity(Map<String, Object> properties) {
+ private static String severity(Map<String, Object> properties) {
String param = (String) properties.get("severity");
if (Strings.isNullOrEmpty(param)) {
throw new IllegalArgumentException("Missing parameter : 'severity'");
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
index 19845815146..6683c79382d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/TransitionAction.java
@@ -20,21 +20,19 @@
package org.sonar.server.issue;
+import com.google.common.base.Predicate;
+import com.google.common.base.Strings;
+import com.google.common.collect.Iterables;
import java.util.Collection;
import java.util.Map;
-
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.issue.Issue;
import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.server.ServerSide;
import org.sonar.core.issue.workflow.IssueWorkflow;
import org.sonar.core.issue.workflow.Transition;
import org.sonar.server.user.UserSession;
-import com.google.common.base.Predicate;
-import com.google.common.base.Strings;
-import com.google.common.collect.Iterables;
-
@ServerSide
public class TransitionAction extends Action {
@@ -77,7 +75,7 @@ public class TransitionAction extends Action {
}, null) != null;
}
- private String transition(Map<String, Object> properties) {
+ private static String transition(Map<String, Object> properties) {
String param = (String) properties.get("transition");
if (Strings.isNullOrEmpty(param)) {
throw new IllegalArgumentException("Missing parameter : 'transition'");
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanService.java b/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanService.java
index 98335080499..7d9b9259753 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanService.java
@@ -22,10 +22,15 @@ package org.sonar.server.issue.actionplan;
import com.google.common.base.Function;
import com.google.common.collect.Iterables;
-import org.sonar.api.server.ServerSide;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import javax.annotation.CheckForNull;
import org.sonar.api.issue.ActionPlan;
import org.sonar.api.issue.internal.DefaultIssue;
import org.sonar.api.issue.internal.IssueChangeContext;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole;
import org.sonar.core.issue.ActionPlanDeadlineComparator;
import org.sonar.core.issue.ActionPlanStats;
@@ -45,13 +50,6 @@ import org.sonar.server.db.DbClient;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;
-import javax.annotation.CheckForNull;
-
-import java.util.Collection;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-
import static com.google.common.collect.Lists.newArrayList;
/**
@@ -205,11 +203,11 @@ public class ActionPlanService {
return resourceDto;
}
- private void checkUserCanAccessProject(String projectKey, UserSession userSession) {
+ private static void checkUserCanAccessProject(String projectKey, UserSession userSession) {
userSession.checkProjectPermission(UserRole.USER, projectKey);
}
- private void checkUserIsProjectAdministrator(String projectKey, UserSession userSession) {
+ private static void checkUserIsProjectAdministrator(String projectKey, UserSession userSession) {
userSession.checkProjectPermission(UserRole.ADMIN, projectKey);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanWs.java b/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanWs.java
index c9b8a51d959..95d980508f0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/actionplan/ActionPlanWs.java
@@ -41,17 +41,17 @@ public class ActionPlanWs implements WebService {
controller.done();
}
- private void defineSearchAction(NewController controller) {
+ private static void defineSearchAction(NewController controller) {
WebService.NewAction action = controller.createAction("search")
.setDescription("Get a list of action plans. Requires Browse permission on project")
.setSince("3.6")
.setHandler(RailsHandler.INSTANCE)
- .setResponseExample(Resources.getResource(this.getClass(), "example-search.json"));
+ .setResponseExample(Resources.getResource(ActionPlanWs.class, "example-search.json"));
addProjectParam(action);
addFormatParam(action);
}
- private void defineCreateAction(NewController controller) {
+ private static void defineCreateAction(NewController controller) {
WebService.NewAction action = controller.createAction("create")
.setDescription("Create an action plan. Requires Administer permission on project")
.setSince("3.6")
@@ -64,7 +64,7 @@ public class ActionPlanWs implements WebService {
addFormatParam(action);
}
- private void defineUpdateAction(NewController controller) {
+ private static void defineUpdateAction(NewController controller) {
WebService.NewAction action = controller.createAction("update")
.setDescription("Update an action plan. Requires Administer permission on project")
.setSince("3.6")
@@ -77,7 +77,7 @@ public class ActionPlanWs implements WebService {
addFormatParam(action);
}
- private void defineDeleteAction(NewController controller) {
+ private static void defineDeleteAction(NewController controller) {
WebService.NewAction action = controller.createAction("delete")
.setDescription("Delete an action plan. Requires Administer permission on project")
.setSince("3.6")
@@ -87,7 +87,7 @@ public class ActionPlanWs implements WebService {
addFormatParam(action);
}
- private void defineOpenAction(NewController controller) {
+ private static void defineOpenAction(NewController controller) {
WebService.NewAction action = controller.createAction("open")
.setDescription("Open an action plan. Requires Administer permission on project")
.setSince("3.6")
@@ -97,7 +97,7 @@ public class ActionPlanWs implements WebService {
addFormatParam(action);
}
- private void defineCloseAction(NewController controller) {
+ private static void defineCloseAction(NewController controller) {
WebService.NewAction action = controller.createAction("close")
.setDescription("Close an action plan. Requires Administer permission on project")
.setSince("3.6")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
index 37311ccfdea..8727dde142c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/IssuesWs.java
@@ -75,12 +75,12 @@ public class IssuesWs implements WebService {
defineBulkChangeAction(controller);
}
- private void defineChangelogAction(NewController controller) {
+ private static void defineChangelogAction(NewController controller) {
WebService.NewAction action = controller.createAction(CHANGELOG_ACTION)
.setDescription("Display changelog of an issue")
.setSince("4.1")
.setHandler(RailsHandler.INSTANCE)
- .setResponseExample(Resources.getResource(this.getClass(), "example-changelog.json"));
+ .setResponseExample(Resources.getResource(IssuesWs.class, "example-changelog.json"));
action.createParam("issue")
.setDescription("Key of the issue")
@@ -89,7 +89,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineAssignAction(NewController controller) {
+ private static void defineAssignAction(NewController controller) {
WebService.NewAction action = controller.createAction(ASSIGN_ACTION)
.setDescription("Assign/Unassign an issue. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -106,7 +106,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineAddCommentAction(NewController controller) {
+ private static void defineAddCommentAction(NewController controller) {
WebService.NewAction action = controller.createAction(ADD_COMMENT_ACTION)
.setDescription("Add a comment. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -123,7 +123,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineDeleteCommentAction(NewController controller) {
+ private static void defineDeleteCommentAction(NewController controller) {
WebService.NewAction action = controller.createAction(DELETE_COMMENT_ACTION)
.setDescription("Delete a comment. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -136,7 +136,7 @@ public class IssuesWs implements WebService {
.setExampleValue("392160d3-a4f2-4c52-a565-e4542cfa2096");
}
- private void defineEditCommentAction(NewController controller) {
+ private static void defineEditCommentAction(NewController controller) {
WebService.NewAction action = controller.createAction(EDIT_COMMENT_ACTION)
.setDescription("Edit a comment. Requires authentication and User role on project")
.setSince("3.6")
@@ -153,7 +153,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineSetSeverityAction(NewController controller) {
+ private static void defineSetSeverityAction(NewController controller) {
WebService.NewAction action = controller.createAction(SET_SEVERITY_ACTION)
.setDescription("Change severity. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -171,7 +171,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void definePlanAction(NewController controller) {
+ private static void definePlanAction(NewController controller) {
WebService.NewAction action = controller.createAction(PLAN_ACTION)
.setDescription("Plan/Unplan an issue. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -188,7 +188,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineDoTransitionAction(NewController controller) {
+ private static void defineDoTransitionAction(NewController controller) {
WebService.NewAction action = controller.createAction(DO_TRANSITION_ACTION)
.setDescription("Do workflow transition on an issue. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -206,12 +206,12 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineTransitionsAction(NewController controller) {
+ private static void defineTransitionsAction(NewController controller) {
WebService.NewAction action = controller.createAction(TRANSITIONS_ACTION)
.setDescription("Get Possible Workflow Transitions for an Issue. Requires Browse permission on project")
.setSince("3.6")
.setHandler(RailsHandler.INSTANCE)
- .setResponseExample(Resources.getResource(this.getClass(), "example-transitions.json"));
+ .setResponseExample(Resources.getResource(IssuesWs.class, "example-transitions.json"));
action.createParam("issue")
.setDescription("Key of the issue")
@@ -219,7 +219,7 @@ public class IssuesWs implements WebService {
.setExampleValue("5bccd6e8-f525-43a2-8d76-fcb13dde79ef");
}
- private void defineCreateAction(NewController controller) {
+ private static void defineCreateAction(NewController controller) {
WebService.NewAction action = controller.createAction(CREATE_ACTION)
.setDescription("Create a manual issue. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -248,7 +248,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineDoActionAction(NewController controller) {
+ private static void defineDoActionAction(NewController controller) {
WebService.NewAction action = controller.createAction(DO_ACTION_ACTION)
.setDescription("Do workflow transition on an issue. Requires authentication and Browse permission on project")
.setSince("3.6")
@@ -265,7 +265,7 @@ public class IssuesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineBulkChangeAction(NewController controller) {
+ private static void defineBulkChangeAction(NewController controller) {
WebService.NewAction action = controller.createAction(BULK_CHANGE_ACTION)
.setDescription("Bulk change on issues. Requires authentication and User role on project(s)")
.setSince("3.7")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
index c5ebc6cdf5a..69166273420 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/issue/ws/SearchAction.java
@@ -684,7 +684,7 @@ public class SearchAction implements IssuesWsAction {
json.endArray();
}
- private void writeUsers(JsonWriter json, Map<String, User> usersByLogin) {
+ private static void writeUsers(JsonWriter json, Map<String, User> usersByLogin) {
json.name("users").beginArray();
for (User user : usersByLogin.values()) {
json.beginObject()
diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java b/server/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java
index 15dfb40895d..9a5968cc965 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/measure/MeasureFilterSql.java
@@ -23,16 +23,6 @@ import com.google.common.base.Function;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
-import org.apache.commons.dbutils.DbUtils;
-import org.apache.commons.lang.StringEscapeUtils;
-import org.apache.commons.lang.StringUtils;
-import org.sonar.core.component.SnapshotDto;
-import org.sonar.core.persistence.Database;
-import org.sonar.core.persistence.dialect.MsSql;
-import org.sonar.core.persistence.dialect.Oracle;
-
-import javax.annotation.Nullable;
-
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
@@ -40,6 +30,14 @@ import java.sql.SQLException;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
+import javax.annotation.Nullable;
+import org.apache.commons.dbutils.DbUtils;
+import org.apache.commons.lang.StringEscapeUtils;
+import org.apache.commons.lang.StringUtils;
+import org.sonar.core.component.SnapshotDto;
+import org.sonar.core.persistence.Database;
+import org.sonar.core.persistence.dialect.MsSql;
+import org.sonar.core.persistence.dialect.Oracle;
class MeasureFilterSql {
@@ -257,7 +255,7 @@ class MeasureFilterSql {
/**
* Replace escape percent and underscore by adding a slash just before
*/
- private String escapePercentAndUnderscrore(String value) {
+ private static String escapePercentAndUnderscrore(String value) {
return value.replaceAll("%", "\\\\%").replaceAll("_", "\\\\_");
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ManualMeasuresWs.java b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ManualMeasuresWs.java
index d585104d646..7a5b3e7900d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ManualMeasuresWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/measure/ws/ManualMeasuresWs.java
@@ -36,7 +36,7 @@ public class ManualMeasuresWs implements WebService {
controller.done();
}
- private void defineIndexAction(NewController controller) {
+ private static void defineIndexAction(NewController controller) {
controller.createAction("index")
.setDescription("Documentation of this web service is available <a href=\"http://redirect.sonarsource.com/doc/old-web-service-api.html\">here</a>")
.setSince("2.10")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java b/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java
index 32abdb0fa67..f25def734f5 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/metric/persistence/MetricDao.java
@@ -37,6 +37,7 @@ import org.sonar.core.persistence.DaoComponent;
import org.sonar.core.persistence.DaoUtils;
import org.sonar.core.persistence.DbSession;
import org.sonar.server.es.SearchOptions;
+import org.sonar.server.exceptions.NotFoundException;
import static com.google.common.collect.Lists.newArrayList;
@@ -57,6 +58,14 @@ public class MetricDao implements DaoComponent {
});
}
+ public MetricDto selectByKey(DbSession session, String key) {
+ MetricDto metric = selectNullableByKey(session, key);
+ if (metric == null) {
+ throw new NotFoundException(String.format("Metric '%s' not found", key));
+ }
+ return metric;
+ }
+
public List<MetricDto> selectEnabled(DbSession session) {
return mapper(session).selectAllEnabled();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java
index d1511cea26c..09c73b50494 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/CreateAction.java
@@ -116,7 +116,7 @@ public class CreateAction implements MetricsWsAction {
}
}
- private MetricDto newMetricTemplate(Request request) {
+ private static MetricDto newMetricTemplate(Request request) {
String key = request.mandatoryParam(PARAM_KEY);
String name = request.mandatoryParam(PARAM_NAME);
String type = Metric.ValueType.valueOf(request.mandatoryParam(PARAM_TYPE)).name();
@@ -158,6 +158,9 @@ public class CreateAction implements MetricsWsAction {
.setUserManaged(true)
.setDirection(0)
.setQualitative(false)
+ .setHidden(false)
+ .setOptimizedBestValue(false)
+ .setDeleteHistoricalData(false)
.setOrigin("GUI");
dbClient.metricDao().insert(dbSession, metric);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricsWs.java b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricsWs.java
index 64360c053c6..c48cd47d533 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricsWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/metric/ws/MetricsWs.java
@@ -47,7 +47,7 @@ public class MetricsWs implements WebService {
controller.done();
}
- private void defineIndexAction(NewController controller) {
+ private static void defineIndexAction(NewController controller) {
controller.createAction("index")
.setDescription("Documentation of this web service is available <a href=\"http://redirect.sonarsource.com/doc/old-web-service-api.html\">here</a>")
.setSince("2.6")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java b/server/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java
index 5a7f011a7ba..bcfcecbddb8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/permission/InternalPermissionService.java
@@ -20,8 +20,12 @@
package org.sonar.server.permission;
-import org.sonar.api.server.ServerSide;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.web.UserRole;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.permission.GlobalPermissions;
@@ -36,12 +40,6 @@ import org.sonar.server.exceptions.ForbiddenException;
import org.sonar.server.issue.index.IssueAuthorizationIndexer;
import org.sonar.server.user.UserSession;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.List;
-import java.util.Map;
-
/**
* Used by ruby code <pre>Internal.permissions</pre>
*/
@@ -261,7 +259,7 @@ public class InternalPermissionService {
}
}
- private Object badRequestIfNullResult(@Nullable Object component, String objectType, String objectKey) {
+ private static Object badRequestIfNullResult(@Nullable Object component, String objectType, String objectKey) {
if (component == null) {
throw new BadRequestException(String.format(NOT_FOUND_FORMAT, objectType, objectKey));
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionFinder.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionFinder.java
index e6d65ddd300..0f380a30dbe 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionFinder.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionFinder.java
@@ -21,9 +21,12 @@ package org.sonar.server.permission;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.security.DefaultGroups;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.Paging;
import org.sonar.core.permission.GroupWithPermission;
import org.sonar.core.permission.GroupWithPermissionDto;
@@ -38,11 +41,6 @@ import org.sonar.core.resource.ResourceDto;
import org.sonar.core.resource.ResourceQuery;
import org.sonar.server.exceptions.NotFoundException;
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.List;
-
import static com.google.common.collect.Lists.newArrayList;
@ServerSide
@@ -97,7 +95,7 @@ public class PermissionFinder {
return new UserWithPermissionQueryResult(toUserWithPermissionList(dtos), hasMoreResults);
}
- private List<UserWithPermission> toUserWithPermissionList(List<UserWithPermissionDto> dtos) {
+ private static List<UserWithPermission> toUserWithPermissionList(List<UserWithPermissionDto> dtos) {
List<UserWithPermission> users = newArrayList();
for (UserWithPermissionDto dto : dtos) {
users.add(dto.toUserWithPermission());
@@ -106,7 +104,7 @@ public class PermissionFinder {
}
@Nullable
- private Long componentId(String componentKey) {
+ private Long componentId(@Nullable String componentKey) {
if (componentKey == null) {
return null;
} else {
@@ -135,13 +133,13 @@ public class PermissionFinder {
return dto.getId();
}
- private int offset(PermissionQuery query) {
+ private static int offset(PermissionQuery query) {
int pageSize = query.pageSize();
int pageIndex = query.pageIndex();
return (pageIndex - 1) * pageSize;
}
- private int limit(PermissionQuery query) {
+ private static int limit(PermissionQuery query) {
// Add one to page size in order to be able to know if there's more results or not
return query.pageSize() + 1;
}
@@ -176,7 +174,7 @@ public class PermissionFinder {
}
}
- private List<GroupWithPermission> pagedGroups(Collection<GroupWithPermissionDto> dtos, Paging paging) {
+ private static List<GroupWithPermission> pagedGroups(Collection<GroupWithPermissionDto> dtos, Paging paging) {
List<GroupWithPermission> groups = newArrayList();
int index = 0;
for (GroupWithPermissionDto dto : dtos) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionQueryParser.java b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionQueryParser.java
index 0384a735ef6..8d16f383bb6 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionQueryParser.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/permission/PermissionQueryParser.java
@@ -20,6 +20,8 @@
package org.sonar.server.permission;
+import org.sonar.api.server.ws.WebService.SelectionMode;
+
import org.sonar.core.permission.PermissionQuery;
import org.sonar.core.user.GroupMembershipQuery;
import org.sonar.server.util.RubyUtils;
@@ -28,9 +30,6 @@ import java.util.Map;
public class PermissionQueryParser {
- private static final String SELECTED_MEMBERSHIP = "selected";
- private static final String DESELECTED_MEMBERSHIP = "deselected";
-
private PermissionQueryParser(){
// Utility class
}
@@ -48,10 +47,10 @@ public class PermissionQueryParser {
}
private static String membership(Map<String, Object> params) {
- String selected = (String) params.get("selected");
- if (SELECTED_MEMBERSHIP.equals(selected)) {
+ SelectionMode selectionMode = SelectionMode.fromParam((String) params.get("selected"));
+ if (SelectionMode.SELECTED == selectionMode) {
return GroupMembershipQuery.IN;
- } else if (DESELECTED_MEMBERSHIP.equals(selected)) {
+ } else if (SelectionMode.DESELECTED == selectionMode) {
return GroupMembershipQuery.OUT;
} else {
return GroupMembershipQuery.ANY;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWs.java b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWs.java
index 4ad77024acf..1bc071d8dbf 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/permission/ws/PermissionsWs.java
@@ -41,7 +41,7 @@ public class PermissionsWs implements WebService {
controller.done();
}
- private void defineAddAction(NewController controller) {
+ private static void defineAddAction(NewController controller) {
NewAction action = controller.createAction("add")
.setDescription("Add a global or a project permission. Requires Administer System permission for global permissions, " +
"requires Administer permission on project for project permissions")
@@ -65,7 +65,7 @@ public class PermissionsWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineRemoveAction(NewController controller) {
+ private static void defineRemoveAction(NewController controller) {
NewAction action = controller.createAction("remove")
.setDescription("Remove a global or a project permission. Requires Administer System permission for global permissions, " +
"requires Administer permission on project for project permissions")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java b/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java
index 01fefe7ee5c..ea59dff20af 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/platform/BackendCleanup.java
@@ -19,6 +19,8 @@
*/
package org.sonar.server.platform;
+import java.sql.Connection;
+import java.sql.SQLException;
import org.apache.commons.dbutils.DbUtils;
import org.elasticsearch.index.query.QueryBuilders;
import org.sonar.api.server.ServerSide;
@@ -32,9 +34,6 @@ import org.sonar.server.search.IndexDefinition;
import org.sonar.server.source.index.SourceLineIndexDefinition;
import org.sonar.server.view.index.ViewIndexDefinition;
-import java.sql.Connection;
-import java.sql.SQLException;
-
@ServerSide
public class BackendCleanup {
@@ -138,7 +137,7 @@ public class BackendCleanup {
}
}
- private void deleteWhereResourceIdNotNull(String tableName, Connection connection) {
+ private static void deleteWhereResourceIdNotNull(String tableName, Connection connection) {
try {
connection.prepareStatement("DELETE FROM " + tableName + " WHERE resource_id IS NOT NULL").execute();
// commit is useless on some databases
@@ -148,7 +147,7 @@ public class BackendCleanup {
}
}
- private void deleteManualRules(Connection connection) {
+ private static void deleteManualRules(Connection connection) {
try {
connection.prepareStatement("DELETE FROM rules WHERE rules.plugin_name='manual'").execute();
// commit is useless on some databases
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java
index 52293fdc6c8..8c36a26c2c7 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/BulkDeleteAction.java
@@ -38,7 +38,7 @@ import java.util.List;
public class BulkDeleteAction implements ProjectsWsAction {
private static final String ACTION = "bulk_delete";
- public static final String PARAM_UUIDS = "ids";
+ public static final String PARAM_IDS = "ids";
public static final String PARAM_KEYS = "keys";
private final ComponentCleanerService componentCleanerService;
@@ -61,8 +61,8 @@ public class BulkDeleteAction implements ProjectsWsAction {
.setHandler(this);
action
- .createParam(PARAM_UUIDS)
- .setDescription("List of project UUIDs to delete")
+ .createParam(PARAM_IDS)
+ .setDescription("List of project ids to delete")
.setExampleValue("ce4c03d6-430f-40a9-b777-ad877c00aa4d,c526ef20-131b-4486-9357-063fa64b5079");
action
@@ -74,7 +74,7 @@ public class BulkDeleteAction implements ProjectsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
userSession.checkGlobalPermission(UserRole.ADMIN);
- List<String> uuids = request.paramAsStrings(PARAM_UUIDS);
+ List<String> uuids = request.paramAsStrings(PARAM_IDS);
List<String> keys = request.paramAsStrings(PARAM_KEYS);
DbSession dbSession = dbClient.openSession(false);
@@ -96,6 +96,6 @@ public class BulkDeleteAction implements ProjectsWsAction {
return dbClient.componentDao().selectByKeys(dbSession, keys);
}
- throw new IllegalArgumentException("UUIDs or keys must be provided");
+ throw new IllegalArgumentException("ids or keys must be provided");
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/project/ws/DeleteAction.java b/server/sonar-server/src/main/java/org/sonar/server/project/ws/DeleteAction.java
index 4665a53ff2d..46a8659d781 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/project/ws/DeleteAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/project/ws/DeleteAction.java
@@ -37,7 +37,7 @@ import org.sonar.server.user.UserSession;
public class DeleteAction implements ProjectsWsAction {
private static final String ACTION = "delete";
- public static final String PARAM_UUID = "id";
+ public static final String PARAM_ID = "id";
public static final String PARAM_KEY = "key";
private final ComponentCleanerService componentCleanerService;
@@ -60,8 +60,8 @@ public class DeleteAction implements ProjectsWsAction {
.setHandler(this);
action
- .createParam(PARAM_UUID)
- .setDescription("Project UUID")
+ .createParam(PARAM_ID)
+ .setDescription("Project id")
.setExampleValue("ce4c03d6-430f-40a9-b777-ad877c00aa4d");
action
@@ -72,7 +72,7 @@ public class DeleteAction implements ProjectsWsAction {
@Override
public void handle(Request request, Response response) throws Exception {
- String uuid = request.param(PARAM_UUID);
+ String uuid = request.param(PARAM_ID);
String key = request.param(PARAM_KEY);
checkPermissions(uuid, key);
@@ -109,6 +109,6 @@ public class DeleteAction implements ProjectsWsAction {
return dbClient.componentDao().selectByKey(dbSession, key);
}
- throw new IllegalArgumentException("UUID or key must be provided");
+ throw new IllegalArgumentException("Id or key must be provided");
}
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QGatesWs.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QGatesWs.java
index bb8bff8abba..514e8d4a655 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QGatesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/QGatesWs.java
@@ -31,7 +31,6 @@ public class QGatesWs implements WebService {
static final String PARAM_PAGE_SIZE = "pageSize";
static final String PARAM_PAGE = "page";
static final String PARAM_QUERY = "query";
- static final String PARAM_SELECTED = "selected";
static final String PARAM_NAME = "name";
static final String PARAM_ERROR = "error";
static final String PARAM_WARNING = "warning";
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java
index 24ccf061c53..69268b929ec 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/SearchAction.java
@@ -20,6 +20,8 @@
package org.sonar.server.qualitygate.ws;
+import org.sonar.api.server.ws.WebService.Param;
+
import com.google.common.io.Resources;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
@@ -54,11 +56,7 @@ public class SearchAction implements QGateWsAction {
.setDescription("To search for projects containing this string. If this parameter is set, \"selected\" is set to \"all\".")
.setExampleValue("abc");
- action.createParam(QGatesWs.PARAM_SELECTED)
- .setDescription("If \"selected\", search for projects associated to the quality gate")
- .setDefaultValue(ProjectQgateAssociationQuery.IN)
- .setPossibleValues(ProjectQgateAssociationQuery.AVAILABLE_MEMBERSHIP)
- .setExampleValue(ProjectQgateAssociationQuery.OUT);
+ action.addSelectionModeParam();
action.createParam(QGatesWs.PARAM_PAGE)
.setDescription("Page number")
@@ -74,7 +72,7 @@ public class SearchAction implements QGateWsAction {
public void handle(Request request, Response response) {
QgateProjectFinder.Association associations = projectFinder.find(ProjectQgateAssociationQuery.builder()
.gateId(request.mandatoryParam(QGatesWs.PARAM_GATE_ID))
- .membership(request.param(QGatesWs.PARAM_QUERY) == null ? request.param(QGatesWs.PARAM_SELECTED) : ProjectQgateAssociationQuery.ANY)
+ .membership(request.param(QGatesWs.PARAM_QUERY) == null ? request.param(Param.SELECTED) : ProjectQgateAssociationQuery.ANY)
.projectSearch(request.param(QGatesWs.PARAM_QUERY))
.pageIndex(request.paramAsInt(QGatesWs.PARAM_PAGE))
.pageSize(request.paramAsInt(QGatesWs.PARAM_PAGE_SIZE))
@@ -83,7 +81,7 @@ public class SearchAction implements QGateWsAction {
writer.beginObject().prop("more", associations.hasMoreResults());
writer.name("results").beginArray();
for (ProjectQgateAssociation project : associations.projects()) {
- writer.beginObject().prop("id", project.id()).prop("name", project.name()).prop(QGatesWs.PARAM_SELECTED, project.isMember()).endObject();
+ writer.beginObject().prop("id", project.id()).prop("name", project.name()).prop(Param.SELECTED, project.isMember()).endObject();
}
writer.endArray().endObject().close();
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java
index 9b53247017f..ce575a74b2c 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualitygate/ws/ShowAction.java
@@ -21,6 +21,8 @@
package org.sonar.server.qualitygate.ws;
import com.google.common.io.Resources;
+import java.util.Collection;
+import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService;
@@ -30,10 +32,6 @@ import org.sonar.core.qualitygate.db.QualityGateDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.qualitygate.QualityGates;
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-
public class ShowAction implements QGateWsAction {
private final QualityGates qualityGates;
@@ -82,7 +80,7 @@ public class ShowAction implements QGateWsAction {
writer.endObject().close();
}
- private void checkOneOfIdOrNamePresent(@Nullable Long qGateId, @Nullable String qGateName) {
+ private static void checkOneOfIdOrNamePresent(@Nullable Long qGateId, @Nullable String qGateName) {
if (qGateId == null && qGateName == null) {
throw new BadRequestException("Either one of 'id' or 'name' is required.");
} else if (qGateId != null && qGateName != null) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java
index bb6555adf7b..e650081860d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileBackuper.java
@@ -23,14 +23,25 @@ import com.google.common.base.Joiner;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import java.io.Reader;
+import java.io.Writer;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.Nullable;
+import javax.xml.stream.XMLInputFactory;
+import javax.xml.stream.XMLStreamException;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.CompareToBuilder;
import org.codehaus.staxmate.SMInputFactory;
import org.codehaus.staxmate.in.SMHierarchicCursor;
import org.codehaus.staxmate.in.SMInputCursor;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.text.XmlWriter;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
@@ -38,19 +49,6 @@ import org.sonar.server.db.DbClient;
import org.sonar.server.qualityprofile.index.ActiveRuleIndex;
import org.sonar.server.search.IndexClient;
-import javax.annotation.Nullable;
-import javax.xml.stream.XMLInputFactory;
-import javax.xml.stream.XMLStreamException;
-
-import java.io.Reader;
-import java.io.Writer;
-import java.util.Collections;
-import java.util.Comparator;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
@ServerSide
public class QProfileBackuper {
@@ -79,7 +77,7 @@ public class QProfileBackuper {
writeXml(writer, profile, activeRules.iterator());
}
- private void writeXml(Writer writer, QualityProfileDto profile, Iterator<ActiveRule> activeRules) {
+ private static void writeXml(Writer writer, QualityProfileDto profile, Iterator<ActiveRule> activeRules) {
XmlWriter xml = XmlWriter.of(writer).declaration();
xml.begin("profile");
xml.prop("name", profile.getName());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
index da3c19f3033..c6eb4c00038 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileExporters.java
@@ -19,9 +19,19 @@
*/
package org.sonar.server.qualityprofile;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.io.Writer;
+import java.nio.charset.StandardCharsets;
+import java.util.ArrayList;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.profiles.ProfileExporter;
import org.sonar.api.profiles.ProfileImporter;
import org.sonar.api.profiles.RulesProfile;
@@ -29,24 +39,13 @@ import org.sonar.api.rules.ActiveRuleParam;
import org.sonar.api.rules.Rule;
import org.sonar.api.rules.RuleFinder;
import org.sonar.api.rules.RulePriority;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.utils.ValidationMessages;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.qualityprofile.db.QualityProfileDto;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
-import java.io.InputStream;
-import java.io.InputStreamReader;
-import java.io.Reader;
-import java.io.StringReader;
-import java.io.StringWriter;
-import java.io.Writer;
-import java.nio.charset.StandardCharsets;
-import java.util.ArrayList;
-import java.util.Iterator;
-import java.util.List;
-import java.util.Map;
-
@ServerSide
public class QProfileExporters {
@@ -169,7 +168,7 @@ public class QProfileExporters {
throw new BadRequestException("No such importer : " + importerKey);
}
- private void processValidationMessages(ValidationMessages messages, QProfileResult result) {
+ private static void processValidationMessages(ValidationMessages messages, QProfileResult result) {
if (!messages.getErrors().isEmpty()) {
throw new BadRequestException(messages);
}
@@ -177,7 +176,7 @@ public class QProfileExporters {
result.addInfos(messages.getInfos());
}
- private RuleActivation toRuleActivation(org.sonar.api.rules.ActiveRule activeRule) {
+ private static RuleActivation toRuleActivation(org.sonar.api.rules.ActiveRule activeRule) {
RuleActivation ruleActivation = new RuleActivation(activeRule.getRule().ruleKey());
ruleActivation.setSeverity(activeRule.getSeverity().name());
for (ActiveRuleParam activeRuleParam : activeRule.getActiveRuleParams()) {
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java
index 267b066a80b..10b67a6499f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfileProjectOperations.java
@@ -122,11 +122,11 @@ public class QProfileProjectOperations {
return qualityProfile;
}
- private void checkPermission(UserSession userSession) {
+ private static void checkPermission(UserSession userSession) {
userSession.checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
}
- private void checkPermission(UserSession userSession, String projectKey) {
+ private static void checkPermission(UserSession userSession, String projectKey) {
if (!userSession.hasGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN) && !userSession.hasProjectPermission(UserRole.ADMIN, projectKey)) {
throw new ForbiddenException("Insufficient privileges");
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java
index e2f65444e5e..3edc390eaa9 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/QProfiles.java
@@ -20,18 +20,15 @@
package org.sonar.server.qualityprofile;
+import com.google.common.base.Strings;
import java.util.List;
-
import javax.annotation.CheckForNull;
-
-import org.sonar.api.server.ServerSide;
import org.sonar.api.component.Component;
+import org.sonar.api.server.ServerSide;
import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.user.UserSession;
import org.sonar.server.util.Validation;
-import com.google.common.base.Strings;
-
/**
* Use {@link org.sonar.server.qualityprofile.QProfileService} instead
*/
@@ -121,7 +118,7 @@ public class QProfiles {
projectOperations.removeAllProjects(profileKey, userSession);
}
- private void checkProfileNameParam(String name) {
+ private static void checkProfileNameParam(String name) {
if (Strings.isNullOrEmpty(name)) {
throw new BadRequestException("quality_profiles.please_type_profile_name");
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java
index b5ee1953bd5..af618145579 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProfilesWs.java
@@ -44,12 +44,12 @@ public class ProfilesWs implements WebService {
controller.done();
}
- private void defineListAction(NewController controller) {
+ private static void defineListAction(NewController controller) {
WebService.NewAction action = controller.createAction("list")
.setDescription("Get a list of profiles")
.setSince("3.3")
.setHandler(RailsHandler.INSTANCE)
- .setResponseExample(Resources.getResource(this.getClass(), "example-list.json"));
+ .setResponseExample(Resources.getResource(ProfilesWs.class, "example-list.json"));
action.createParam("language")
.setDescription("Profile language")
@@ -60,12 +60,12 @@ public class ProfilesWs implements WebService {
RailsHandler.addJsonOnlyFormatParam(action);
}
- private void defineIndexAction(NewController controller) {
+ private static void defineIndexAction(NewController controller) {
WebService.NewAction action = controller.createAction("index")
.setDescription("Get a profile")
.setSince("3.3")
.setHandler(RailsHandler.INSTANCE)
- .setResponseExample(Resources.getResource(this.getClass(), "example-index.json"));
+ .setResponseExample(Resources.getResource(ProfilesWs.class, "example-index.json"));
action.createParam("language")
.setDescription("Profile language")
@@ -77,7 +77,7 @@ public class ProfilesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineBackupAction(NewController controller) {
+ private static void defineBackupAction(NewController controller) {
WebService.NewAction action = controller.createAction("backup")
.setDescription("Backup a quality profile. Requires Administer Quality Profiles permission")
.setSince("3.1")
@@ -94,7 +94,7 @@ public class ProfilesWs implements WebService {
RailsHandler.addFormatParam(action);
}
- private void defineRestoreAction(NewController controller) {
+ private static void defineRestoreAction(NewController controller) {
WebService.NewAction action = controller.createAction("restore")
.setDescription("Restore a quality profile backup. Requires Administer Quality Profiles permission")
.setSince("3.1")
@@ -107,7 +107,7 @@ public class ProfilesWs implements WebService {
RailsHandler.addJsonOnlyFormatParam(action);
}
- private void defineDestroyAction(NewController controller) {
+ private static void defineDestroyAction(NewController controller) {
WebService.NewAction action = controller.createAction("destroy")
.setDescription("Delete a quality profile. Requires Administer Quality Profiles permission")
.setSince("3.3")
@@ -124,7 +124,7 @@ public class ProfilesWs implements WebService {
.setExampleValue("Sonar way");
}
- private void defineSetAsDefaultAction(NewController controller) {
+ private static void defineSetAsDefaultAction(NewController controller) {
WebService.NewAction action = controller.createAction("set_as_default")
.setDescription("Set a quality profile as Default. Requires Administer Quality Profiles permission")
.setSince("3.3")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectsAction.java b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectsAction.java
index f4b3bc9658f..fb6349e77e4 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/qualityprofile/ws/ProjectsAction.java
@@ -19,6 +19,9 @@
*/
package org.sonar.server.qualityprofile.ws;
+import org.sonar.api.server.ws.WebService.Param;
+
+import org.sonar.api.server.ws.WebService.SelectionMode;
import com.google.common.base.Predicate;
import com.google.common.collect.Collections2;
import com.google.common.collect.Iterables;
@@ -46,15 +49,10 @@ import java.util.List;
public class ProjectsAction implements QProfileWsAction {
private static final String PARAM_KEY = "key";
- private static final String PARAM_SELECTED = "selected";
private static final String PARAM_QUERY = "query";
private static final String PARAM_PAGE_SIZE = "pageSize";
private static final String PARAM_PAGE = "page";
- private static final String SELECTION_ALL = "all";
- private static final String SELECTION_SELECTED = "selected";
- private static final String SELECTION_DESELECTED = "deselected";
-
private final DbClient dbClient;
private final UserSession userSession;
@@ -74,10 +72,7 @@ public class ProjectsAction implements QProfileWsAction {
.setDescription("A quality profile key.")
.setRequired(true)
.setExampleValue("sonar-way-java-12345");
- projects.createParam(PARAM_SELECTED)
- .setDescription("If specified, return only selected or deselected projects.")
- .setPossibleValues(SELECTION_SELECTED, SELECTION_DESELECTED, SELECTION_ALL)
- .setDefaultValue(SELECTION_ALL);
+ projects.addSelectionModeParam();
projects.createParam(PARAM_QUERY)
.setDescription("If specified, return only projects whose name match the query.");
projects.createParam(PARAM_PAGE_SIZE)
@@ -94,7 +89,7 @@ public class ProjectsAction implements QProfileWsAction {
try {
checkProfileExists(profileKey, session);
- String selected = request.param(PARAM_SELECTED);
+ String selected = request.param(Param.SELECTED);
String query = request.param(PARAM_QUERY);
int pageSize = request.mandatoryParamAsInt(PARAM_PAGE_SIZE);
int page = request.mandatoryParamAsInt(PARAM_PAGE);
@@ -151,9 +146,10 @@ public class ProjectsAction implements QProfileWsAction {
private List<ProjectQprofileAssociationDto> loadProjects(String profileKey, DbSession session, String selected, String query) {
List<ProjectQprofileAssociationDto> projects = Lists.newArrayList();
- if (SELECTION_SELECTED.equals(selected)) {
+ SelectionMode selectionMode = SelectionMode.fromParam(selected);
+ if (SelectionMode.SELECTED == selectionMode) {
projects.addAll(dbClient.qualityProfileDao().selectSelectedProjects(profileKey, query, session));
- } else if (SELECTION_DESELECTED.equals(selected)) {
+ } else if (SelectionMode.DESELECTED == selectionMode) {
projects.addAll(dbClient.qualityProfileDao().selectDeselectedProjects(profileKey, query, session));
} else {
projects.addAll(dbClient.qualityProfileDao().selectProjectAssociations(profileKey, query, session));
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinitionLoader.java b/server/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinitionLoader.java
index ca56bdab178..69bec5d8b1f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinitionLoader.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/DeprecatedRulesDefinitionLoader.java
@@ -21,13 +21,18 @@ package org.sonar.server.rule;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import java.io.Reader;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.rule.RuleKey;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rules.RuleParam;
import org.sonar.api.rules.RuleRepository;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.rule.RuleParamType;
import org.sonar.api.server.rule.RulesDefinition;
@@ -40,13 +45,6 @@ import org.sonar.server.debt.DebtModelXMLExporter;
import org.sonar.server.debt.DebtModelXMLExporter.RuleDebt;
import org.sonar.server.debt.DebtRulesXMLImporter;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.io.Reader;
-import java.util.Collection;
-import java.util.List;
-
import static com.google.common.collect.Lists.newArrayList;
/**
@@ -124,7 +122,7 @@ public class DeprecatedRulesDefinitionLoader {
}
}
- private DebtRemediationFunction remediationFunction(DebtRemediationFunction.Type function, @Nullable String coefficient, @Nullable String offset,
+ private static DebtRemediationFunction remediationFunction(DebtRemediationFunction.Type function, @Nullable String coefficient, @Nullable String offset,
RulesDefinition.DebtRemediationFunctions functions, String repoKey, String ruleKey) {
if (DebtRemediationFunction.Type.LINEAR.equals(function) && coefficient != null) {
return functions.linear(coefficient);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
index d17ef7ef29b..ef3a54b65bc 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/RegisterRules.java
@@ -25,6 +25,14 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.picocontainer.Startable;
@@ -49,11 +57,6 @@ import org.sonar.server.db.DbClient;
import org.sonar.server.qualityprofile.RuleActivator;
import org.sonar.server.startup.RegisterDebtModel;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.*;
-
import static com.google.common.collect.Lists.newArrayList;
/**
@@ -160,7 +163,7 @@ public class RegisterRules implements Startable {
}
@CheckForNull
- private CharacteristicDto characteristic(RulesDefinition.Rule ruleDef, @Nullable Integer overridingCharacteristicId, Map<String, CharacteristicDto> allCharacteristics) {
+ private static CharacteristicDto characteristic(RulesDefinition.Rule ruleDef, @Nullable Integer overridingCharacteristicId, Map<String, CharacteristicDto> allCharacteristics) {
String subCharacteristic = ruleDef.debtSubCharacteristic();
String repo = ruleDef.repository().key();
String ruleKey = ruleDef.key();
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleOperations.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleOperations.java
index f98fe84c8cb..fa4850d7621 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleOperations.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleOperations.java
@@ -21,9 +21,11 @@
package org.sonar.server.rule;
import com.google.common.base.Strings;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.commons.lang.builder.EqualsBuilder;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.rule.RuleKey;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.server.debt.internal.DefaultDebtRemediationFunction;
import org.sonar.core.permission.GlobalPermissions;
@@ -36,9 +38,6 @@ import org.sonar.server.exceptions.BadRequestException;
import org.sonar.server.exceptions.NotFoundException;
import org.sonar.server.user.UserSession;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
/**
* @deprecated to be dropped in 4.4
*/
@@ -151,7 +150,7 @@ public class RuleOperations {
.isEquals();
}
- private void checkPermission(UserSession userSession) {
+ private static void checkPermission(UserSession userSession) {
userSession.checkLoggedIn();
userSession.checkGlobalPermission(GlobalPermissions.QUALITY_PROFILE_ADMIN);
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java
index 8d469629b0a..442d452f1d0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/rule/RuleUpdater.java
@@ -22,12 +22,16 @@ package org.sonar.server.rule;
import com.google.common.base.Strings;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Multimap;
+import java.util.Collections;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
import org.apache.commons.lang.ObjectUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.EqualsBuilder;
-import org.sonar.api.server.ServerSide;
import org.sonar.api.rule.RuleStatus;
import org.sonar.api.rule.Severity;
+import org.sonar.api.server.ServerSide;
import org.sonar.api.server.debt.DebtRemediationFunction;
import org.sonar.api.utils.System2;
import org.sonar.core.persistence.DbSession;
@@ -39,11 +43,6 @@ import org.sonar.core.technicaldebt.db.CharacteristicDto;
import org.sonar.server.db.DbClient;
import org.sonar.server.user.UserSession;
-import java.util.Collections;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
-
import static com.google.common.collect.Lists.newArrayList;
@ServerSide
@@ -141,7 +140,7 @@ public class RuleUpdater {
}
}
- private void updateName(RuleUpdate update, Context context) {
+ private static void updateName(RuleUpdate update, Context context) {
String name = update.getName();
if (Strings.isNullOrEmpty(name)) {
throw new IllegalArgumentException("The name is missing");
@@ -150,7 +149,7 @@ public class RuleUpdater {
}
}
- private void updateDescription(RuleUpdate update, Context context) {
+ private static void updateDescription(RuleUpdate update, Context context) {
String description = update.getMarkdownDescription();
if (Strings.isNullOrEmpty(description)) {
throw new IllegalArgumentException("The description is missing");
@@ -159,7 +158,7 @@ public class RuleUpdater {
}
}
- private void updateSeverity(RuleUpdate update, Context context) {
+ private static void updateSeverity(RuleUpdate update, Context context) {
String severity = update.getSeverity();
if (Strings.isNullOrEmpty(severity) || !Severity.ALL.contains(severity)) {
throw new IllegalArgumentException("The severity is invalid");
@@ -168,7 +167,7 @@ public class RuleUpdater {
}
}
- private void updateStatus(RuleUpdate update, Context context) {
+ private static void updateStatus(RuleUpdate update, Context context) {
RuleStatus status = update.getStatus();
if (status == null) {
throw new IllegalArgumentException("The status is missing");
@@ -177,7 +176,7 @@ public class RuleUpdater {
}
}
- private void updateTags(RuleUpdate update, Context context) {
+ private static void updateTags(RuleUpdate update, Context context) {
Set<String> tags = update.getTags();
if (tags == null || tags.isEmpty()) {
context.rule.setTags(Collections.<String>emptySet());
@@ -186,7 +185,7 @@ public class RuleUpdater {
}
}
- private void updateDebtSubCharacteristic(RuleUpdate update, Context context) {
+ private static void updateDebtSubCharacteristic(RuleUpdate update, Context context) {
if (update.getDebtSubCharacteristicKey() == null) {
// set to "none"
Integer id = context.rule.getDefaultSubCharacteristicId() != null ? RuleDto.DISABLED_CHARACTERISTIC_ID : null;
@@ -216,7 +215,7 @@ public class RuleUpdater {
}
}
- private void updateDebtRemediationFunction(RuleUpdate update, Context context) {
+ private static void updateDebtRemediationFunction(RuleUpdate update, Context context) {
Integer subChar = context.rule.getSubCharacteristicId();
boolean noChar =
(context.rule.getDefaultSubCharacteristicId() == null && subChar == null) ||
diff --git a/server/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java b/server/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java
index 3fc1d2c0b86..8ad8f75fef0 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/search/BaseIndex.java
@@ -23,17 +23,40 @@ import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Multimap;
+import java.io.Serializable;
+import java.util.ArrayDeque;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.NoSuchElementException;
+import java.util.Queue;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.elasticsearch.action.admin.indices.exists.indices.IndicesExistsResponse;
import org.elasticsearch.action.count.CountRequestBuilder;
import org.elasticsearch.action.count.CountResponse;
-import org.elasticsearch.action.get.*;
+import org.elasticsearch.action.get.GetRequestBuilder;
+import org.elasticsearch.action.get.GetResponse;
+import org.elasticsearch.action.get.MultiGetItemResponse;
+import org.elasticsearch.action.get.MultiGetRequest;
+import org.elasticsearch.action.get.MultiGetRequestBuilder;
+import org.elasticsearch.action.get.MultiGetResponse;
import org.elasticsearch.action.search.SearchRequestBuilder;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.action.search.SearchScrollRequestBuilder;
import org.elasticsearch.common.settings.ImmutableSettings;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
-import org.elasticsearch.index.query.*;
+import org.elasticsearch.index.query.BoolFilterBuilder;
+import org.elasticsearch.index.query.FilterBuilder;
+import org.elasticsearch.index.query.FilterBuilders;
+import org.elasticsearch.index.query.QueryBuilder;
+import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.aggregations.Aggregation;
import org.elasticsearch.search.aggregations.AggregationBuilders;
@@ -49,12 +72,6 @@ import org.sonar.api.utils.log.Loggers;
import org.sonar.core.persistence.Dto;
import org.sonar.server.exceptions.NotFoundException;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.io.Serializable;
-import java.util.*;
-
/**
* @deprecated replaced by {@link org.sonar.server.es.BaseIndex}
*/
@@ -273,7 +290,7 @@ public abstract class BaseIndex<DOMAIN, DTO extends Dto<KEY>, KEY extends Serial
}
}
- private Map mapUuidPathField(IndexField field) {
+ private static Map mapUuidPathField(IndexField field) {
return ImmutableMap.of(
"type", "string",
"index", "analyzed",
diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java
index 0a6d74e96ea..c55cbf8f5f3 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/source/HtmlTextDecorator.java
@@ -20,15 +20,13 @@
package org.sonar.server.source;
import com.google.common.io.Closeables;
-import org.sonar.api.utils.log.Loggers;
-
-import javax.annotation.Nullable;
-
import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.util.Collection;
import java.util.List;
+import javax.annotation.Nullable;
+import org.sonar.api.utils.log.Loggers;
import static com.google.common.collect.Lists.newArrayList;
@@ -127,11 +125,11 @@ class HtmlTextDecorator {
}
}
- private boolean canAddLine(int currentLine, @Nullable Integer from) {
+ private static boolean canAddLine(int currentLine, @Nullable Integer from) {
return from == null || currentLine >= from;
}
- private boolean shouldStop(int currentLine, @Nullable Integer to) {
+ private static boolean shouldStop(int currentLine, @Nullable Integer to) {
return to != null && to < currentLine;
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/source/db/FileSourceDao.java b/server/sonar-server/src/main/java/org/sonar/server/source/db/FileSourceDao.java
index 7962fa25364..e17ae11c323 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/source/db/FileSourceDao.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/source/db/FileSourceDao.java
@@ -72,8 +72,9 @@ public class FileSourceDao implements DaoComponent {
ResultSet rs = null;
Reader reader = null;
try {
- pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=? AND data_type = '" + Type.SOURCE +"'");
+ pstmt = connection.prepareStatement("SELECT line_hashes FROM file_sources WHERE file_uuid=? AND data_type=?");
pstmt.setString(1, fileUuid);
+ pstmt.setString(2, Type.SOURCE);
rs = pstmt.executeQuery();
if (rs.next()) {
reader = rs.getCharacterStream(1);
diff --git a/server/sonar-server/src/main/java/org/sonar/server/startup/JdbcDriverDeployer.java b/server/sonar-server/src/main/java/org/sonar/server/startup/JdbcDriverDeployer.java
index 8a38ae75e6a..bf1e09ca327 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/startup/JdbcDriverDeployer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/startup/JdbcDriverDeployer.java
@@ -19,17 +19,15 @@
*/
package org.sonar.server.startup;
+import java.io.File;
+import java.io.IOException;
+import javax.annotation.Nullable;
import org.apache.commons.io.FileUtils;
import org.sonar.api.config.Settings;
import org.sonar.home.cache.FileHashes;
import org.sonar.process.ProcessProperties;
import org.sonar.server.platform.DefaultServerFileSystem;
-import javax.annotation.Nullable;
-
-import java.io.File;
-import java.io.IOException;
-
public class JdbcDriverDeployer {
private final DefaultServerFileSystem fileSystem;
@@ -66,7 +64,7 @@ public class JdbcDriverDeployer {
}
}
- private String driverIndexContent(@Nullable File deployedDriver) {
+ private static String driverIndexContent(@Nullable File deployedDriver) {
if (deployedDriver != null) {
String hash = new FileHashes().of(deployedDriver);
return deployedDriver.getName() + "|" + hash;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/startup/LogServerId.java b/server/sonar-server/src/main/java/org/sonar/server/startup/LogServerId.java
index 5fcbeb02a3e..8cbfb2bdbbe 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/startup/LogServerId.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/startup/LogServerId.java
@@ -61,7 +61,7 @@ public final class LogServerId {
}
}
- private void addQuotedValue(PropertyDto property, StringBuilder message) {
+ private static void addQuotedValue(PropertyDto property, StringBuilder message) {
message.append("\"");
message.append(property.getValue());
message.append("\"\n");
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipFinder.java b/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipFinder.java
index d8e7e988bc1..4e70fa30931 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipFinder.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipFinder.java
@@ -20,6 +20,7 @@
package org.sonar.server.user;
+import java.util.List;
import org.sonar.api.server.ServerSide;
import org.sonar.core.user.GroupMembership;
import org.sonar.core.user.GroupMembershipDao;
@@ -29,8 +30,6 @@ import org.sonar.core.user.UserDao;
import org.sonar.core.user.UserDto;
import org.sonar.server.exceptions.NotFoundException;
-import java.util.List;
-
import static com.google.common.collect.Lists.newArrayList;
@ServerSide
@@ -88,7 +87,7 @@ public class GroupMembershipFinder {
return userDto.getId();
}
- private List<GroupMembership> toGroupMembership(List<GroupMembershipDto> dtos) {
+ private static List<GroupMembership> toGroupMembership(List<GroupMembershipDto> dtos) {
List<GroupMembership> groups = newArrayList();
for (GroupMembershipDto groupMembershipDto : dtos) {
groups.add(groupMembershipDto.toGroupMembership());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipService.java b/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipService.java
index c5932c8b5c0..067a659dc5e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipService.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/GroupMembershipService.java
@@ -20,12 +20,11 @@
package org.sonar.server.user;
+import java.util.Map;
import org.sonar.api.server.ServerSide;
import org.sonar.core.user.GroupMembershipQuery;
import org.sonar.server.util.RubyUtils;
-import java.util.Map;
-
/**
* Used by ruby code <pre>Internal.group_membership</pre>
*/
@@ -55,7 +54,7 @@ public class GroupMembershipService {
return builder.build();
}
- private String membership(Map<String, Object> params) {
+ private static String membership(Map<String, Object> params) {
String selected = (String) params.get("selected");
if (SELECTED_MEMBERSHIP.equals(selected)) {
return GroupMembershipQuery.IN;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexer.java
index 302b522b58c..44532f11e2e 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/index/UserIndexer.java
@@ -20,6 +20,8 @@
package org.sonar.server.user.index;
+import java.sql.Connection;
+import java.util.Iterator;
import org.apache.commons.dbutils.DbUtils;
import org.elasticsearch.action.update.UpdateRequest;
import org.sonar.core.persistence.DbSession;
@@ -28,9 +30,6 @@ import org.sonar.server.es.BaseIndexer;
import org.sonar.server.es.BulkIndexer;
import org.sonar.server.es.EsClient;
-import java.sql.Connection;
-import java.util.Iterator;
-
public class UserIndexer extends BaseIndexer {
private final DbClient dbClient;
@@ -71,7 +70,7 @@ public class UserIndexer extends BaseIndexer {
return maxUpdatedAt;
}
- private UpdateRequest newUpsertRequest(UserDoc user) {
+ private static UpdateRequest newUpsertRequest(UserDoc user) {
return new UpdateRequest(UserIndexDefinition.INDEX, UserIndexDefinition.TYPE_USER, user.login())
.doc(user.getFields())
.upsert(user.getFields());
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/FavoritesWs.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/FavoritesWs.java
index 52c3c89639f..facfd4ec20f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/FavoritesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/FavoritesWs.java
@@ -36,7 +36,7 @@ public class FavoritesWs implements WebService {
controller.done();
}
- private void defineIndexAction(NewController controller) {
+ private static void defineIndexAction(NewController controller) {
controller.createAction("index")
.setDescription("Documentation of this web service is available <a href=\"http://redirect.sonarsource.com/doc/old-web-service-api.html\">here</a>")
.setSince("2.6")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java
index 9538cd93104..b713e9a6ed2 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/GroupsAction.java
@@ -20,12 +20,12 @@
package org.sonar.server.user.ws;
import java.util.List;
-import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.server.ws.WebService.SelectionMode;
import org.sonar.api.utils.Paging;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.permission.GlobalPermissions;
@@ -39,15 +39,10 @@ import org.sonar.server.user.UserSession;
public class GroupsAction implements UsersWsAction {
private static final String PARAM_LOGIN = "login";
- private static final String PARAM_SELECTED = "selected";
- private static final String SELECTION_ALL = "all";
- private static final String SELECTION_SELECTED = PARAM_SELECTED;
- private static final String SELECTION_DESELECTED = "deselected";
-
- private static final String FIELD_SELECTED = PARAM_SELECTED;
- private static final String FIELD_DESCRIPTION = "description";
private static final String FIELD_NAME = "name";
+ private static final String FIELD_DESCRIPTION = "description";
+ private static final String FIELD_SELECTED = "selected";
private final DbClient dbClient;
private final UserSession userSession;
@@ -70,14 +65,9 @@ public class GroupsAction implements UsersWsAction {
.setExampleValue("admin")
.setRequired(true);
- action.createParam(PARAM_SELECTED)
- .setDescription("If specified, only show groups the user is member of (selected) or not (deselected).")
- .setPossibleValues(SELECTION_SELECTED, SELECTION_DESELECTED, SELECTION_ALL)
- .setDefaultValue(SELECTION_ALL);
+ action.addSelectionModeParam();
- action.createParam(Param.TEXT_QUERY)
- .setDescription("If specified, only show groups whose name contains the query.")
- .setExampleValue("user");
+ action.addSearchQuery("users", "group names");
action.addPagingParams(25);
}
@@ -90,7 +80,7 @@ public class GroupsAction implements UsersWsAction {
int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
int page = request.mandatoryParamAsInt(Param.PAGE);
String queryString = request.param(Param.TEXT_QUERY);
- String selected = request.param(PARAM_SELECTED);
+ String selected = request.mandatoryParam(Param.SELECTED);
GroupMembershipQuery query = GroupMembershipQuery.builder()
.login(login)
@@ -116,7 +106,7 @@ public class GroupsAction implements UsersWsAction {
}
}
- private void writeGroups(JsonWriter json, List<GroupMembershipDto> groups) {
+ private static void writeGroups(JsonWriter json, List<GroupMembershipDto> groups) {
json.name("groups").beginArray();
for (GroupMembershipDto group : groups) {
json.beginObject()
@@ -128,17 +118,18 @@ public class GroupsAction implements UsersWsAction {
json.endArray();
}
- private void writePaging(JsonWriter json, Paging paging) {
+ private static void writePaging(JsonWriter json, Paging paging) {
json.prop("p", paging.pageIndex())
.prop("ps", paging.pageSize())
.prop("total", paging.total());
}
- private String getMembership(@Nullable String selected) {
+ private String getMembership(String selected) {
+ SelectionMode selectionMode = SelectionMode.fromParam(selected);
String membership = GroupMembershipQuery.ANY;
- if (SELECTION_SELECTED.equals(selected)) {
+ if (SelectionMode.SELECTED == selectionMode) {
membership = GroupMembershipQuery.IN;
- } else if (SELECTION_DESELECTED.equals(selected)) {
+ } else if (SelectionMode.DESELECTED == selectionMode) {
membership = GroupMembershipQuery.OUT;
}
return membership;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java
index d3cf1fa69fe..22fa4a1b4ed 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UpdateAction.java
@@ -105,7 +105,7 @@ public class UpdateAction implements UsersWsAction {
json.endObject().close();
}
- private void writeUser(JsonWriter json, UserDoc user) {
+ private static void writeUser(JsonWriter json, UserDoc user) {
json.name("user").beginObject()
.prop("login", user.login())
.prop("name", user.name())
diff --git a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserPropertiesWs.java b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserPropertiesWs.java
index f4db43de3e9..976f19834e8 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserPropertiesWs.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/user/ws/UserPropertiesWs.java
@@ -36,7 +36,7 @@ public class UserPropertiesWs implements WebService {
controller.done();
}
- private void defineIndexAction(NewController controller) {
+ private static void defineIndexAction(NewController controller) {
controller.createAction("index")
.setDescription("Documentation of this web service is available <a href=\"http://redirect.sonarsource.com/doc/old-web-service-api.html\">here</a>")
.setSince("2.6")
diff --git a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java
index 526ddd114b9..6cb3a52d35f 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/usergroups/ws/UsersAction.java
@@ -20,12 +20,12 @@
package org.sonar.server.usergroups.ws;
import java.util.List;
-import javax.annotation.Nullable;
import org.sonar.api.server.ws.Request;
import org.sonar.api.server.ws.Response;
import org.sonar.api.server.ws.WebService.NewAction;
import org.sonar.api.server.ws.WebService.NewController;
import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.server.ws.WebService.SelectionMode;
import org.sonar.api.utils.Paging;
import org.sonar.api.utils.text.JsonWriter;
import org.sonar.core.permission.GlobalPermissions;
@@ -40,13 +40,8 @@ import org.sonar.server.user.UserSession;
public class UsersAction implements UserGroupsWsAction {
private static final String PARAM_ID = "id";
- private static final String PARAM_SELECTED = "selected";
- private static final String SELECTION_ALL = "all";
- private static final String SELECTION_SELECTED = PARAM_SELECTED;
- private static final String SELECTION_DESELECTED = "deselected";
-
- private static final String FIELD_SELECTED = PARAM_SELECTED;
+ private static final String FIELD_SELECTED = "selected";
private static final String FIELD_NAME = "name";
private static final String FIELD_LOGIN = "login";
@@ -71,10 +66,7 @@ public class UsersAction implements UserGroupsWsAction {
.setExampleValue("42")
.setRequired(true);
- action.createParam(PARAM_SELECTED)
- .setDescription("If specified, only show users who belong to a group (selected=selected) or only those who do not (selected=deselected).")
- .setPossibleValues(SELECTION_SELECTED, SELECTION_DESELECTED, SELECTION_ALL)
- .setDefaultValue(SELECTION_ALL);
+ action.addSelectionModeParam();
action.addSearchQuery("freddy", "names", "logins");
@@ -89,7 +81,7 @@ public class UsersAction implements UserGroupsWsAction {
int pageSize = request.mandatoryParamAsInt(Param.PAGE_SIZE);
int page = request.mandatoryParamAsInt(Param.PAGE);
String queryString = request.param(Param.TEXT_QUERY);
- String selected = request.param(PARAM_SELECTED);
+ String selected = request.mandatoryParam(Param.SELECTED);
UserMembershipQuery query = UserMembershipQuery.builder()
.groupId(groupId)
@@ -115,7 +107,7 @@ public class UsersAction implements UserGroupsWsAction {
}
}
- private void writeMembers(JsonWriter json, List<UserMembershipDto> users) {
+ private static void writeMembers(JsonWriter json, List<UserMembershipDto> users) {
json.name("users").beginArray();
for (UserMembershipDto user : users) {
json.beginObject()
@@ -127,17 +119,18 @@ public class UsersAction implements UserGroupsWsAction {
json.endArray();
}
- private void writePaging(JsonWriter json, Paging paging) {
+ private static void writePaging(JsonWriter json, Paging paging) {
json.prop(Param.PAGE, paging.pageIndex())
.prop(Param.PAGE_SIZE, paging.pageSize())
.prop("total", paging.total());
}
- private String getMembership(@Nullable String selected) {
+ private String getMembership(String selected) {
+ SelectionMode selectionMode = SelectionMode.fromParam(selected);
String membership = GroupMembershipQuery.ANY;
- if (SELECTION_SELECTED.equals(selected)) {
+ if (SelectionMode.SELECTED == selectionMode) {
membership = GroupMembershipQuery.IN;
- } else if (SELECTION_DESELECTED.equals(selected)) {
+ } else if (SelectionMode.DESELECTED == selectionMode) {
membership = GroupMembershipQuery.OUT;
}
return membership;
diff --git a/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java b/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java
index b63a332be9c..b718dbe094d 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/util/CloseableIterator.java
@@ -20,6 +20,7 @@
package org.sonar.server.util;
import com.google.common.base.Throwables;
+import java.io.Closeable;
import java.util.Iterator;
import java.util.NoSuchElementException;
import javax.annotation.CheckForNull;
@@ -59,28 +60,8 @@ public abstract class CloseableIterator<O> implements Iterator<O>, AutoCloseable
public static <T> CloseableIterator<T> from(final Iterator<T> iterator) {
// early fail
requireNonNull(iterator);
- checkArgument(!(iterator instanceof CloseableIterator), "This method does not support creating a CloseableIterator from a CloseableIterator");
- return new CloseableIterator<T>() {
- @Override
- public boolean hasNext() {
- return iterator.hasNext();
- }
-
- @Override
- public T next() {
- return iterator.next();
- }
-
- @Override
- protected T doNext() {
- throw new UnsupportedOperationException("hasNext has been override, doNext is never called");
- }
-
- @Override
- protected void doClose() throws Exception {
- // do nothing
- }
- };
+ checkArgument(!(iterator instanceof AutoCloseable), "This method does not support creating a CloseableIterator from an Iterator which is Closeable");
+ return new RegularIteratorWrapper<>(iterator);
}
private O nextObject = null;
@@ -157,4 +138,31 @@ public abstract class CloseableIterator<O> implements Iterator<O>, AutoCloseable
protected abstract void doClose() throws Exception;
+ private static class RegularIteratorWrapper<T> extends CloseableIterator<T> {
+ private final Iterator<T> iterator;
+
+ public RegularIteratorWrapper(Iterator<T> iterator) {
+ this.iterator = iterator;
+ }
+
+ @Override
+ public boolean hasNext() {
+ return iterator.hasNext();
+ }
+
+ @Override
+ public T next() {
+ return iterator.next();
+ }
+
+ @Override
+ protected T doNext() {
+ throw new UnsupportedOperationException("hasNext has been override, doNext is never called");
+ }
+
+ @Override
+ protected void doClose() throws Exception {
+ // do nothing
+ }
+ }
}
diff --git a/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java
index 93944e0cb38..1c12e86c163 100644
--- a/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java
+++ b/server/sonar-server/src/main/java/org/sonar/server/view/index/ViewIndexer.java
@@ -20,6 +20,8 @@
package org.sonar.server.view.index;
+import java.util.List;
+import java.util.Map;
import org.elasticsearch.action.update.UpdateRequest;
import org.sonar.core.component.ComponentDto;
import org.sonar.core.component.UuidWithProjectUuidDto;
@@ -30,9 +32,6 @@ import org.sonar.server.es.BulkIndexer;
import org.sonar.server.es.EsClient;
import org.sonar.server.issue.index.IssueIndex;
-import java.util.List;
-import java.util.Map;
-
import static com.google.common.collect.Maps.newHashMap;
public class ViewIndexer extends BaseIndexer {
@@ -121,7 +120,7 @@ public class ViewIndexer extends BaseIndexer {
}
}
- private UpdateRequest newUpsertRequest(ViewDoc doc) {
+ private static UpdateRequest newUpsertRequest(ViewDoc doc) {
return new UpdateRequest(ViewIndexDefinition.INDEX, ViewIndexDefinition.TYPE_VIEW, doc.uuid())
.doc(doc.getFields())
.upsert(doc.getFields());
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/DbComponentsRefCacheTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImplTest.java
index 67c20dfa9b2..6f369f7906b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/component/DbComponentsRefCacheTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/BatchReportDirectoryHolderImplTest.java
@@ -17,29 +17,26 @@
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
+package org.sonar.server.computation.batch;
-package org.sonar.server.computation.component;
-
+import java.io.File;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
-public class DbComponentsRefCacheTest {
-
- @Test
- public void add_and_get_component() throws Exception {
- DbComponentsRefCache cache = new DbComponentsRefCache();
- cache.addComponent(1, new DbComponentsRefCache.DbComponent(10L, "Key", "Uuid"));
+public class BatchReportDirectoryHolderImplTest {
- assertThat(cache.getByRef(1)).isNotNull();
- assertThat(cache.getByRef(1).getId()).isEqualTo(10L);
- assertThat(cache.getByRef(1).getKey()).isEqualTo("Key");
- assertThat(cache.getByRef(1).getUuid()).isEqualTo("Uuid");
+ @Test(expected = IllegalStateException.class)
+ public void getDirectory_throws_ISE_if_holder_is_empty() {
+ new BatchReportDirectoryHolderImpl().getDirectory();
}
- @Test(expected = IllegalArgumentException.class)
- public void fail_on_unknown_ref() throws Exception {
- new DbComponentsRefCache().getByRef(1);
- }
+ @Test
+ public void getDirectory_returns_File_set_with_setDirectory() {
+ File file = new File("");
+ BatchReportDirectoryHolderImpl holder = new BatchReportDirectoryHolderImpl();
+ holder.setDirectory(file);
+ assertThat(holder.getDirectory()).isSameAs(file);
+ }
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/batch/ComponentTreeRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/ComponentTreeRule.java
new file mode 100644
index 00000000000..db6e2bc5710
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/ComponentTreeRule.java
@@ -0,0 +1,127 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.batch;
+
+import com.google.common.base.Function;
+import com.google.common.collect.Iterables;
+import java.util.Objects;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import org.junit.rules.TestRule;
+import org.junit.runner.Description;
+import org.junit.runners.model.Statement;
+import org.sonar.batch.protocol.output.BatchReport;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.ComponentImpl;
+import org.sonar.server.computation.component.DumbComponent;
+
+public class ComponentTreeRule implements TestRule {
+
+ @CheckForNull
+ private final BatchReportReader batchReportReader;
+ private final BUILD_OPTIONS buildOptions;
+
+ private Component root;
+
+ private ComponentTreeRule(BatchReportReader batchReportReader, BUILD_OPTIONS buildOptions) {
+ this.batchReportReader = batchReportReader;
+ this.buildOptions = buildOptions;
+ }
+
+ public static ComponentTreeRule from(BatchReportReader batchReportReader, BUILD_OPTIONS buildOptions) {
+ return new ComponentTreeRule(Objects.requireNonNull(batchReportReader), buildOptions);
+ }
+
+ public static ComponentTreeRule from(BatchReportReader batchReportReader) {
+ return new ComponentTreeRule(Objects.requireNonNull(batchReportReader), BUILD_OPTIONS.NONE);
+ }
+
+ @Override
+ public Statement apply(final Statement statement, Description description) {
+ return new Statement() {
+ @Override
+ public void evaluate() throws Throwable {
+ try {
+ statement.evaluate();
+ } finally {
+ clear();
+ }
+ }
+ };
+ }
+
+ private void clear() {
+ this.root = null;
+ }
+
+ public enum BUILD_OPTIONS {
+ NONE(false, false), KEY(false, true), UUID(true, false), KEY_AND_UUID(true, true);
+ private final boolean uuid;
+ private final boolean key;
+
+ BUILD_OPTIONS(boolean uuid, boolean key) {
+ this.uuid = uuid;
+ this.key = key;
+ }
+ }
+
+ public Component getRoot() {
+ if (root == null) {
+ buildComponentRoot(buildOptions);
+ }
+ return this.root;
+ }
+
+ private Component buildComponentRoot(BUILD_OPTIONS build_options) {
+ int rootComponentRef = batchReportReader.readMetadata().getRootComponentRef();
+ return newComponent(batchReportReader.readComponent(rootComponentRef), build_options);
+ }
+
+ private DumbComponent newComponent(BatchReport.Component component, BUILD_OPTIONS build_options) {
+ return new DumbComponent(
+ ComponentImpl.convertType(component.getType()),
+ component.getRef(),
+ build_options.uuid ? uuidOf(component.getRef()) : null,
+ build_options.key ? keyOf(component.getRef()) : null,
+ buildChildren(component, build_options));
+ }
+
+ private Component[] buildChildren(BatchReport.Component component, final BUILD_OPTIONS build_options) {
+ return Iterables.toArray(
+ Iterables.transform(
+ component.getChildRefList(),
+ new Function<Integer, Component>() {
+ @Override
+ public Component apply(@Nonnull Integer componentRef) {
+ return newComponent(batchReportReader.readComponent(componentRef), build_options);
+ }
+ }
+ ), Component.class);
+ }
+
+ public String keyOf(int ref) {
+ return "key_" + ref;
+ }
+
+ public String uuidOf(int ref) {
+ return "uuid_" + ref;
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java
index b3ca3251ddd..c715cfbabb2 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/batch/TreeRootHolderRule.java
@@ -19,15 +19,21 @@
*/
package org.sonar.server.computation.batch;
+import java.util.HashMap;
+import java.util.Map;
import java.util.Objects;
import org.junit.rules.TestRule;
import org.junit.runner.Description;
import org.junit.runners.model.Statement;
import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor;
import org.sonar.server.computation.component.TreeRootHolder;
+import static org.sonar.server.computation.component.DepthTraversalTypeAwareVisitor.Order.POST_ORDER;
+
public class TreeRootHolderRule implements TestRule, TreeRootHolder {
private Component root;
+ private Map<Integer, Component> componentsByRef = new HashMap<>();
@Override
public Statement apply(final Statement statement, Description description) {
@@ -55,7 +61,26 @@ public class TreeRootHolderRule implements TestRule, TreeRootHolder {
return root;
}
+ @Override
+ public Component getComponentByRef(int ref) {
+ if (root == null) {
+ throw new IllegalStateException("Root has not been set in " + TreeRootHolder.class.getSimpleName());
+ }
+
+ Component component = componentsByRef.get(ref);
+ if (component == null) {
+ throw new IllegalArgumentException(String.format("Component '%s' hasn't been found", ref));
+ }
+ return component;
+ }
+
public void setRoot(Component newRoot) {
this.root = Objects.requireNonNull(newRoot);
+ new DepthTraversalTypeAwareVisitor(Component.Type.FILE, POST_ORDER) {
+ @Override
+ public void visitAny(Component component) {
+ componentsByRef.put(component.getRef(), component);
+ }
+ }.visit(root);
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentImplTest.java
index d5ba594bfa8..3100ab9a1f9 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/component/ComponentImplTest.java
@@ -29,6 +29,11 @@ import static org.assertj.core.api.Assertions.assertThat;
public class ComponentImplTest {
private ComponentImpl component = new ComponentImpl(BatchReport.Component.newBuilder().build(), Collections.<Component>emptyList());
+ @Test(expected = NullPointerException.class)
+ public void constructor_throws_NPE_if_component_arg_is_Null() {
+ new ComponentImpl(null, null);
+ }
+
@Test(expected = UnsupportedOperationException.class)
public void getUuid_throws_UOE_if_uuid_has_not_been_set_yet() {
component.getUuid();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/DbIdsRepositoryTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/DbIdsRepositoryTest.java
new file mode 100644
index 00000000000..d2c30aae8b4
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/component/DbIdsRepositoryTest.java
@@ -0,0 +1,62 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.computation.component;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.ExpectedException;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class DbIdsRepositoryTest {
+
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
+ Component component = DumbComponent.DUMB_PROJECT;
+
+ @Test
+ public void add_and_get_component() throws Exception {
+ DbIdsRepository cache = new DbIdsRepository();
+ cache.setComponentId(component, 10L);
+
+ assertThat(cache.getComponentId(component)).isEqualTo(10L);
+ }
+
+ @Test
+ public void fail_on_unknown_ref() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Component ref '" + component.getRef() + "' has no component id");
+
+ new DbIdsRepository().getComponentId(DumbComponent.DUMB_PROJECT);
+ }
+
+ @Test
+ public void fail_if_component_id_already_set() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ thrown.expectMessage("Component ref '" + component.getRef() + "' has already a component id");
+
+ DbIdsRepository cache = new DbIdsRepository();
+ cache.setComponentId(component, 10L);
+ cache.setComponentId(component, 11L);
+ }
+
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/component/TreeRootHolderImplTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/component/TreeRootHolderImplTest.java
index 1613b765545..679b708ef18 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/component/TreeRootHolderImplTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/component/TreeRootHolderImplTest.java
@@ -19,29 +19,62 @@
*/
package org.sonar.server.computation.component;
+import org.junit.Rule;
import org.junit.Test;
+import org.junit.rules.ExpectedException;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
public class TreeRootHolderImplTest {
+ @Rule
+ public ExpectedException thrown = ExpectedException.none();
+
TreeRootHolderImpl treeRootHolder = new TreeRootHolderImpl();
- Component component = mock(Component.class);
+ Component project = DumbComponent.DUMB_PROJECT;
- @Test(expected = NullPointerException.class)
+ @Test
public void setRoot_throws_NPE_if_arg_is_null() {
+ thrown.expect(NullPointerException.class);
treeRootHolder.setRoot(null);
}
- @Test(expected = IllegalStateException.class)
+ @Test
public void getRoot_throws_ISE_if_root_has_not_been_set_yet() {
+ thrown.expect(IllegalStateException.class);
treeRootHolder.getRoot();
}
@Test
public void verify_setRoot_getRoot() {
- treeRootHolder.setRoot(component);
- assertThat(treeRootHolder.getRoot()).isSameAs(component);
+ treeRootHolder.setRoot(project);
+ assertThat(treeRootHolder.getRoot()).isSameAs(project);
+ }
+
+ @Test
+ public void get_by_ref() throws Exception {
+ Component file = new DumbComponent(Component.Type.FILE, 4, null, null);
+ Component directory = new DumbComponent(Component.Type.DIRECTORY, 3, null, null, file);
+ Component module = new DumbComponent(Component.Type.MODULE, 2, null, null, directory);
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, null, null, module);
+ treeRootHolder.setRoot(project);
+
+ assertThat(treeRootHolder.getComponentByRef(1)).isEqualTo(project);
+ assertThat(treeRootHolder.getComponentByRef(2)).isEqualTo(module);
+ assertThat(treeRootHolder.getComponentByRef(3)).isEqualTo(directory);
+ assertThat(treeRootHolder.getComponentByRef(4)).isEqualTo(file);
+ }
+
+ @Test
+ public void fail_to_get_by_ref_if_root_not_set() throws Exception {
+ thrown.expect(IllegalStateException.class);
+ treeRootHolder.getComponentByRef(project.getRef());
+ }
+
+ @Test
+ public void fail_to_get_by_ref_if_ref_not_found() throws Exception {
+ thrown.expect(IllegalArgumentException.class);
+ treeRootHolder.setRoot(project);
+ treeRootHolder.getComponentByRef(123);
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java
index 286f58c79cd..e77c23cfff9 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/ApplyPermissionsStepTest.java
@@ -45,7 +45,7 @@ import org.sonar.server.component.ComponentTesting;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.computation.batch.TreeRootHolderRule;
import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.DbIdsRepository;
import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.server.es.EsTester;
@@ -63,8 +63,10 @@ public class ApplyPermissionsStepTest extends BaseStepTest {
@ClassRule
public static EsTester esTester = new EsTester().addDefinitions(new IssueIndexDefinition(new Settings()));
+
@ClassRule
public static DbTester dbTester = new DbTester();
+
@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
@@ -74,7 +76,7 @@ public class ApplyPermissionsStepTest extends BaseStepTest {
Settings settings;
- DbComponentsRefCache dbComponentsRefCache;
+ DbIdsRepository dbIdsRepository;
IssueAuthorizationIndexer issueAuthorizationIndexer;
ApplyPermissionsStep step;
@@ -94,10 +96,10 @@ public class ApplyPermissionsStepTest extends BaseStepTest {
issueAuthorizationIndexer = new IssueAuthorizationIndexer(dbClient, esTester.client());
issueAuthorizationIndexer.setEnabled(true);
- dbComponentsRefCache = new DbComponentsRefCache();
+ dbIdsRepository = new DbIdsRepository();
- step = new ApplyPermissionsStep(dbClient, dbComponentsRefCache, issueAuthorizationIndexer, new PermissionFacade(roleDao, null,
- new ResourceDao(dbTester.myBatis(), System2.INSTANCE), permissionTemplateDao, settings), treeRootHolder);
+ step = new ApplyPermissionsStep(dbClient, dbIdsRepository, issueAuthorizationIndexer, new PermissionFacade(roleDao, null,
+ new ResourceDao(dbTester.myBatis(), System2.INSTANCE), permissionTemplateDao, settings), treeRootHolder);
}
@After
@@ -116,8 +118,9 @@ public class ApplyPermissionsStepTest extends BaseStepTest {
dbClient.permissionTemplateDao().addGroupPermission(permissionTemplateDto.getId(), null, UserRole.USER);
dbSession.commit();
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(projectDto.getId(), PROJECT_KEY, PROJECT_UUID));
- treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, PROJECT_KEY, PROJECT_UUID));
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, PROJECT_UUID, PROJECT_KEY);
+ dbIdsRepository.setComponentId(project, projectDto.getId());
+ treeRootHolder.setRoot(project);
step.execute();
dbSession.commit();
@@ -143,8 +146,9 @@ public class ApplyPermissionsStepTest extends BaseStepTest {
dbSession.commit();
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(projectDto.getId(), PROJECT_KEY, PROJECT_UUID));
- treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, PROJECT_KEY, PROJECT_UUID));
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, PROJECT_UUID, PROJECT_KEY);
+ dbIdsRepository.setComponentId(project, projectDto.getId());
+ treeRootHolder.setRoot(project);
step.execute();
dbSession.commit();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java
index c28d1a7a30c..de876131970 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexComponentsStepTest.java
@@ -23,38 +23,35 @@ package org.sonar.server.computation.step;
import java.io.IOException;
import org.junit.Rule;
import org.junit.Test;
-import org.sonar.batch.protocol.output.BatchReport;
-import org.sonar.core.component.ComponentDto;
import org.sonar.core.resource.ResourceIndexerDao;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.DbComponentsRefCache.DbComponent;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.DumbComponent;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
public class IndexComponentsStepTest extends BaseStepTest {
private static final String PROJECT_KEY = "PROJECT_KEY";
@Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+ @Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
ResourceIndexerDao resourceIndexerDao = mock(ResourceIndexerDao.class);
- DbComponentsRefCache dbComponentsRefCache = new DbComponentsRefCache();
- IndexComponentsStep sut = new IndexComponentsStep(resourceIndexerDao, dbComponentsRefCache, reportReader);
+ DbIdsRepository dbIdsRepository = new DbIdsRepository();
+ IndexComponentsStep sut = new IndexComponentsStep(resourceIndexerDao, dbIdsRepository, treeRootHolder);
@Test
public void call_indexProject_of_dao() throws IOException {
- dbComponentsRefCache.addComponent(1, new DbComponent(123L, PROJECT_KEY, "PROJECT_UUID"));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
- ComponentDto project = mock(ComponentDto.class);
- when(project.getId()).thenReturn(123L);
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "PROJECT_UUID", PROJECT_KEY);
+ dbIdsRepository.setComponentId(project, 123L);
+ treeRootHolder.setRoot(project);
sut.execute();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java
index 9ff56d86d8c..d088251659c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexSourceLinesStepTest.java
@@ -27,10 +27,10 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.Settings;
-import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.persistence.DbTester;
-import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.server.es.EsTester;
import org.sonar.server.source.db.FileSourceDao;
@@ -43,43 +43,37 @@ import static org.assertj.core.api.Assertions.assertThat;
public class IndexSourceLinesStepTest extends BaseStepTest {
- private static final String PROJECT_KEY = "PROJECT_KEY";
-
@ClassRule
public static DbTester dbTester = new DbTester();
+
@ClassRule
public static EsTester esTester = new EsTester().addDefinitions(new SourceLineIndexDefinition(new Settings()));
+
@Rule
- public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
DbClient dbClient;
- DbComponentsRefCache dbComponentsRefCache;
@Before
public void setUp() {
dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new FileSourceDao(null));
- dbComponentsRefCache = new DbComponentsRefCache();
}
@Override
protected ComputationStep step() {
SourceLineIndexer sourceLineIndexer = new SourceLineIndexer(dbClient, esTester.client());
sourceLineIndexer.setEnabled(true);
- return new IndexSourceLinesStep(sourceLineIndexer, dbComponentsRefCache, reportReader);
+ return new IndexSourceLinesStep(sourceLineIndexer, treeRootHolder);
}
@Test
public void index_source() throws Exception {
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
-
dbTester.prepareDbUnit(getClass(), "index_source.xml");
Connection connection = dbTester.openConnection();
FileSourceTesting.updateDataColumn(connection, "FILE1_UUID", FileSourceTesting.newRandomData(1).build());
connection.close();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", "PROJECT_KEY"));
step().execute();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexTestsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexTestsStepTest.java
index 3970cbcc031..b36e572c090 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexTestsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/IndexTestsStepTest.java
@@ -28,10 +28,10 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.config.Settings;
-import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.persistence.DbTester;
-import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.server.es.EsTester;
import org.sonar.server.source.db.FileSourceDao;
@@ -46,40 +46,36 @@ public class IndexTestsStepTest extends BaseStepTest {
@ClassRule
public static DbTester dbTester = new DbTester();
+
@ClassRule
public static EsTester esTester = new EsTester().addDefinitions(new TestIndexDefinition(new Settings()));
+
@Rule
- public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
DbClient dbClient;
- DbComponentsRefCache dbComponentsRefCache;
@Before
public void setUp() {
dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new FileSourceDao(null));
esTester.truncateIndices();
- dbComponentsRefCache = new DbComponentsRefCache();
}
@Override
protected ComputationStep step() {
TestIndexer testIndexer = new TestIndexer(dbClient, esTester.client());
testIndexer.setEnabled(true);
- return new IndexTestsStep(testIndexer, dbComponentsRefCache, reportReader);
+ return new IndexTestsStep(testIndexer, treeRootHolder);
}
@Test
public void index_test() throws Exception {
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, "PROJECT_KEY", "ABCD"));
-
dbTester.prepareDbUnit(getClass(), "index_source.xml");
Connection connection = dbTester.openConnection();
TestTesting.updateDataColumn(connection, "FILE1_UUID", TestTesting.newRandomTests(1));
connection.close();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", "PROJECT_KEY"));
step().execute();
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsAndSnapshotsStepTest.java
index e91e84168f9..6ff9fce279b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistComponentsAndSnapshotsStepTest.java
@@ -26,6 +26,7 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
+import org.sonar.api.utils.System2;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.component.ComponentDto;
@@ -36,7 +37,7 @@ import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.computation.batch.BatchReportReaderRule;
import org.sonar.server.computation.batch.TreeRootHolderRule;
import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.component.DbIdsRepository;
import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.test.DbTests;
@@ -45,22 +46,28 @@ import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.mock;
@Category(DbTests.class)
-public class PersistComponentsStepTest extends BaseStepTest {
+public class PersistComponentsAndSnapshotsStepTest extends BaseStepTest {
private static final String PROJECT_KEY = "PROJECT_KEY";
@ClassRule
public static DbTester dbTester = new DbTester();
- @Rule
- public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+ @Rule
+ public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
+ System2 system2 = mock(System2.class);
+
+ DbIdsRepository dbIdsRepository;
+
DbSession session;
+
DbClient dbClient;
- DbComponentsRefCache dbComponentsRefCache;
- PersistComponentsStep sut;
+ PersistComponentsAndSnapshotsStep sut;
@Before
public void setup() throws Exception {
@@ -68,8 +75,10 @@ public class PersistComponentsStepTest extends BaseStepTest {
session = dbTester.myBatis().openSession(false);
dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new ComponentDao());
- dbComponentsRefCache = new DbComponentsRefCache();
- sut = new PersistComponentsStep(dbClient, dbComponentsRefCache, reportReader, treeRootHolder);
+ reportReader.setMetadata(BatchReport.Metadata.newBuilder().build());
+
+ dbIdsRepository = new DbIdsRepository();
+ sut = new PersistComponentsAndSnapshotsStep(system2, dbClient, treeRootHolder, reportReader, dbIdsRepository);
}
@Override
@@ -84,10 +93,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
@Test
public void persist_components() throws Exception {
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -118,79 +123,77 @@ public class PersistComponentsStepTest extends BaseStepTest {
.setLanguage("java")
.build());
- treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
- new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY",
- new DumbComponent(Component.Type.DIRECTORY, 3, "CDEF", "MODULE_KEY:src/main/java/dir",
- new DumbComponent(Component.Type.FILE, 4, "DEFG", "MODULE_KEY:src/main/java/dir/Foo.java")))));
+ Component file = new DumbComponent(Component.Type.FILE, 4, "DEFG", "MODULE_KEY:src/main/java/dir/Foo.java");
+ Component directory = new DumbComponent(Component.Type.DIRECTORY, 3, "CDEF", "MODULE_KEY:src/main/java/dir", file);
+ Component module = new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY", directory);
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, module);
+ treeRootHolder.setRoot(project);
+
sut.execute();
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
- ComponentDto project = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY);
- assertThat(project).isNotNull();
- assertThat(project.name()).isEqualTo("Project");
- assertThat(project.description()).isEqualTo("Project description");
- assertThat(project.path()).isNull();
- assertThat(project.uuid()).isEqualTo("ABCD");
- assertThat(project.moduleUuid()).isNull();
- assertThat(project.moduleUuidPath()).isEqualTo("." + project.uuid() + ".");
- assertThat(project.projectUuid()).isEqualTo(project.uuid());
- assertThat(project.qualifier()).isEqualTo("TRK");
- assertThat(project.scope()).isEqualTo("PRJ");
- assertThat(project.parentProjectId()).isNull();
-
- ComponentDto module = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY");
- assertThat(module).isNotNull();
- assertThat(module.name()).isEqualTo("Module");
- assertThat(module.description()).isEqualTo("Module description");
- assertThat(module.path()).isEqualTo("module");
- assertThat(module.uuid()).isEqualTo("BCDE");
- assertThat(module.moduleUuid()).isEqualTo(project.uuid());
- assertThat(module.moduleUuidPath()).isEqualTo(project.moduleUuidPath() + module.uuid() + ".");
- assertThat(module.projectUuid()).isEqualTo(project.uuid());
- assertThat(module.qualifier()).isEqualTo("BRC");
- assertThat(module.scope()).isEqualTo("PRJ");
- assertThat(module.parentProjectId()).isEqualTo(project.getId());
-
- ComponentDto directory = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir");
- assertThat(directory).isNotNull();
- assertThat(directory.name()).isEqualTo("src/main/java/dir");
- assertThat(directory.description()).isNull();
- assertThat(directory.path()).isEqualTo("src/main/java/dir");
- assertThat(directory.uuid()).isEqualTo("CDEF");
- assertThat(directory.moduleUuid()).isEqualTo(module.uuid());
- assertThat(directory.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
- assertThat(directory.projectUuid()).isEqualTo(project.uuid());
- assertThat(directory.qualifier()).isEqualTo("DIR");
- assertThat(directory.scope()).isEqualTo("DIR");
- assertThat(directory.parentProjectId()).isEqualTo(module.getId());
-
- ComponentDto file = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir/Foo.java");
- assertThat(file).isNotNull();
- assertThat(file.name()).isEqualTo("Foo.java");
- assertThat(file.description()).isNull();
- assertThat(file.path()).isEqualTo("src/main/java/dir/Foo.java");
- assertThat(file.language()).isEqualTo("java");
- assertThat(file.uuid()).isEqualTo("DEFG");
- assertThat(file.moduleUuid()).isEqualTo(module.uuid());
- assertThat(file.moduleUuidPath()).isEqualTo(module.moduleUuidPath());
- assertThat(file.projectUuid()).isEqualTo(project.uuid());
- assertThat(file.qualifier()).isEqualTo("FIL");
- assertThat(file.scope()).isEqualTo("FIL");
- assertThat(file.parentProjectId()).isEqualTo(module.getId());
-
- assertThat(dbComponentsRefCache.getByRef(1).getId()).isEqualTo(project.getId());
- assertThat(dbComponentsRefCache.getByRef(2).getId()).isEqualTo(module.getId());
- assertThat(dbComponentsRefCache.getByRef(3).getId()).isEqualTo(directory.getId());
- assertThat(dbComponentsRefCache.getByRef(4).getId()).isEqualTo(file.getId());
+ ComponentDto projectDto = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY);
+ assertThat(projectDto).isNotNull();
+ assertThat(projectDto.name()).isEqualTo("Project");
+ assertThat(projectDto.description()).isEqualTo("Project description");
+ assertThat(projectDto.path()).isNull();
+ assertThat(projectDto.uuid()).isEqualTo("ABCD");
+ assertThat(projectDto.moduleUuid()).isNull();
+ assertThat(projectDto.moduleUuidPath()).isEqualTo("." + projectDto.uuid() + ".");
+ assertThat(projectDto.projectUuid()).isEqualTo(projectDto.uuid());
+ assertThat(projectDto.qualifier()).isEqualTo("TRK");
+ assertThat(projectDto.scope()).isEqualTo("PRJ");
+ assertThat(projectDto.parentProjectId()).isNull();
+
+ ComponentDto moduleDto = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY");
+ assertThat(moduleDto).isNotNull();
+ assertThat(moduleDto.name()).isEqualTo("Module");
+ assertThat(moduleDto.description()).isEqualTo("Module description");
+ assertThat(moduleDto.path()).isEqualTo("module");
+ assertThat(moduleDto.uuid()).isEqualTo("BCDE");
+ assertThat(moduleDto.moduleUuid()).isEqualTo(projectDto.uuid());
+ assertThat(moduleDto.moduleUuidPath()).isEqualTo(projectDto.moduleUuidPath() + moduleDto.uuid() + ".");
+ assertThat(moduleDto.projectUuid()).isEqualTo(projectDto.uuid());
+ assertThat(moduleDto.qualifier()).isEqualTo("BRC");
+ assertThat(moduleDto.scope()).isEqualTo("PRJ");
+ assertThat(moduleDto.parentProjectId()).isEqualTo(projectDto.getId());
+
+ ComponentDto directoryDto = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir");
+ assertThat(directoryDto).isNotNull();
+ assertThat(directoryDto.name()).isEqualTo("src/main/java/dir");
+ assertThat(directoryDto.description()).isNull();
+ assertThat(directoryDto.path()).isEqualTo("src/main/java/dir");
+ assertThat(directoryDto.uuid()).isEqualTo("CDEF");
+ assertThat(directoryDto.moduleUuid()).isEqualTo(moduleDto.uuid());
+ assertThat(directoryDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath());
+ assertThat(directoryDto.projectUuid()).isEqualTo(projectDto.uuid());
+ assertThat(directoryDto.qualifier()).isEqualTo("DIR");
+ assertThat(directoryDto.scope()).isEqualTo("DIR");
+ assertThat(directoryDto.parentProjectId()).isEqualTo(moduleDto.getId());
+
+ ComponentDto fileDto = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY:src/main/java/dir/Foo.java");
+ assertThat(fileDto).isNotNull();
+ assertThat(fileDto.name()).isEqualTo("Foo.java");
+ assertThat(fileDto.description()).isNull();
+ assertThat(fileDto.path()).isEqualTo("src/main/java/dir/Foo.java");
+ assertThat(fileDto.language()).isEqualTo("java");
+ assertThat(fileDto.uuid()).isEqualTo("DEFG");
+ assertThat(fileDto.moduleUuid()).isEqualTo(moduleDto.uuid());
+ assertThat(fileDto.moduleUuidPath()).isEqualTo(moduleDto.moduleUuidPath());
+ assertThat(fileDto.projectUuid()).isEqualTo(projectDto.uuid());
+ assertThat(fileDto.qualifier()).isEqualTo("FIL");
+ assertThat(fileDto.scope()).isEqualTo("FIL");
+ assertThat(fileDto.parentProjectId()).isEqualTo(moduleDto.getId());
+
+ assertThat(dbIdsRepository.getComponentId(project)).isEqualTo(projectDto.getId());
+ assertThat(dbIdsRepository.getComponentId(module)).isEqualTo(moduleDto.getId());
+ assertThat(dbIdsRepository.getComponentId(directory)).isEqualTo(directoryDto.getId());
+ assertThat(dbIdsRepository.getComponentId(file)).isEqualTo(fileDto.getId());
}
@Test
public void persist_file_directly_attached_on_root_directory() throws Exception {
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -213,6 +216,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
new DumbComponent(Component.Type.DIRECTORY, 2, "CDEF", PROJECT_KEY + ":/",
new DumbComponent(Component.Type.FILE, 3, "DEFG", PROJECT_KEY + ":pom.xml"))));
+
sut.execute();
ComponentDto directory = dbClient.componentDao().selectNullableByKey(session, "PROJECT_KEY:/");
@@ -228,10 +232,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
@Test
public void persist_unit_test() throws Exception {
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -255,6 +255,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
new DumbComponent(Component.Type.DIRECTORY, 2, "CDEF", PROJECT_KEY + ":src/test/java/dir",
new DumbComponent(Component.Type.FILE, 3, "DEFG", PROJECT_KEY + ":src/test/java/dir/FooTest.java"))));
+
sut.execute();
ComponentDto file = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY + ":src/test/java/dir/FooTest.java");
@@ -274,10 +275,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
dbClient.componentDao().insert(session, module);
session.commit();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -286,28 +283,29 @@ public class PersistComponentsStepTest extends BaseStepTest {
.addChildRef(2)
.build());
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(2)
- .setType(Constants.ComponentType.MODULE)
- .setKey("MODULE_KEY")
- .setName("Module")
- .addChildRef(3)
- .build());
+ .setRef(2)
+ .setType(Constants.ComponentType.MODULE)
+ .setKey("MODULE_KEY")
+ .setName("Module")
+ .addChildRef(3)
+ .build());
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(3)
- .setType(Constants.ComponentType.DIRECTORY)
- .setPath("src/main/java/dir")
- .addChildRef(4)
- .build());
+ .setRef(3)
+ .setType(Constants.ComponentType.DIRECTORY)
+ .setPath("src/main/java/dir")
+ .addChildRef(4)
+ .build());
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(4)
- .setType(Constants.ComponentType.FILE)
- .setPath("src/main/java/dir/Foo.java")
- .build());
+ .setRef(4)
+ .setType(Constants.ComponentType.FILE)
+ .setPath("src/main/java/dir/Foo.java")
+ .build());
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY",
new DumbComponent(Component.Type.DIRECTORY, 3, "CDEF", "MODULE_KEY:src/main/java/dir",
new DumbComponent(Component.Type.FILE, 4, "DEFG", "MODULE_KEY:src/main/java/dir/Foo.java")))));
+
sut.execute();
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
@@ -341,10 +339,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
@Test
public void compute_parent_project_id() throws Exception {
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -384,6 +378,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
new DumbComponent(Component.Type.MODULE, 3, "CDEF", "SUB_MODULE_1_KEY",
new DumbComponent(Component.Type.MODULE, 4, "DEFG", "SUB_MODULE_2_KEY",
new DumbComponent(Component.Type.DIRECTORY, 5, "EFGH", "SUB_MODULE_2_KEY:src/main/java/dir"))))));
+
sut.execute();
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
@@ -411,10 +406,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
@Test
public void persist_multi_modules() throws Exception {
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -447,6 +438,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_A",
new DumbComponent(Component.Type.MODULE, 3, "DEFG", "SUB_MODULE_A")),
new DumbComponent(Component.Type.MODULE, 4, "CDEF", "MODULE_B")));
+
sut.execute();
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
@@ -487,17 +479,13 @@ public class PersistComponentsStepTest extends BaseStepTest {
dbClient.componentDao().insert(session, directory, file);
session.commit();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(1)
- .setType(Constants.ComponentType.PROJECT)
- .setKey(PROJECT_KEY)
- .setName("Project")
- .addChildRef(2)
- .build());
+ .setRef(1)
+ .setType(Constants.ComponentType.PROJECT)
+ .setKey(PROJECT_KEY)
+ .setName("Project")
+ .addChildRef(2)
+ .build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(2)
.setType(Constants.ComponentType.MODULE)
@@ -506,21 +494,22 @@ public class PersistComponentsStepTest extends BaseStepTest {
.addChildRef(3)
.build());
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(3)
- .setType(Constants.ComponentType.DIRECTORY)
- .setPath("src/main/java/dir")
- .addChildRef(4)
- .build());
+ .setRef(3)
+ .setType(Constants.ComponentType.DIRECTORY)
+ .setPath("src/main/java/dir")
+ .addChildRef(4)
+ .build());
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(4)
- .setType(Constants.ComponentType.FILE)
- .setPath("src/main/java/dir/Foo.java")
- .build());
+ .setRef(4)
+ .setType(Constants.ComponentType.FILE)
+ .setPath("src/main/java/dir/Foo.java")
+ .build());
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY",
new DumbComponent(Component.Type.DIRECTORY, 3, "CDEF", "MODULE_KEY:src/main/java/dir",
new DumbComponent(Component.Type.FILE, 4, "DEFG", "MODULE_KEY:src/main/java/dir/Foo.java")))));
+
sut.execute();
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(4);
@@ -574,27 +563,24 @@ public class PersistComponentsStepTest extends BaseStepTest {
dbClient.componentDao().insert(session, module);
session.commit();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(1)
- .setType(Constants.ComponentType.PROJECT)
- .setKey(PROJECT_KEY)
- .setName("New project name")
- .addChildRef(2)
- .build());
+ .setRef(1)
+ .setType(Constants.ComponentType.PROJECT)
+ .setKey(PROJECT_KEY)
+ .setName("New project name")
+ .addChildRef(2)
+ .build());
reportReader.putComponent(BatchReport.Component.newBuilder()
- .setRef(2)
- .setType(Constants.ComponentType.MODULE)
- .setKey("MODULE_KEY")
- .setName("New module name")
- .setPath("New path")
- .build());
+ .setRef(2)
+ .setType(Constants.ComponentType.MODULE)
+ .setKey("MODULE_KEY")
+ .setName("New module name")
+ .setPath("New path")
+ .build());
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY")));
+
sut.execute();
ComponentDto projectReloaded = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY);
@@ -612,10 +598,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
dbClient.componentDao().insert(session, module);
session.commit();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -634,6 +616,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY")));
+
sut.execute();
ComponentDto projectReloaded = dbClient.componentDao().selectNullableByKey(session, PROJECT_KEY);
@@ -651,10 +634,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
dbClient.componentDao().insert(session, module);
session.commit();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -672,6 +651,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY,
new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY")));
+
sut.execute();
ComponentDto moduleReloaded = dbClient.componentDao().selectNullableByKey(session, "MODULE_KEY");
@@ -690,10 +670,6 @@ public class PersistComponentsStepTest extends BaseStepTest {
dbClient.componentDao().insert(session, directory, file);
session.commit();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -733,6 +709,7 @@ public class PersistComponentsStepTest extends BaseStepTest {
new DumbComponent(Component.Type.MODULE, 3, "BCDE", "MODULE_B",
new DumbComponent(Component.Type.DIRECTORY, 4, "CDEF", "MODULE_B:src/main/java/dir",
new DumbComponent(Component.Type.FILE, 5, "DEFG", "MODULE_B:src/main/java/dir/Foo.java"))))));
+
sut.execute();
assertThat(dbTester.countRowsOfTable("projects")).isEqualTo(5);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java
index 04b283d6a83..c61cfb73622 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistDuplicationsStepTest.java
@@ -27,7 +27,6 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
-import org.sonar.api.config.Settings;
import org.sonar.api.measures.CoreMetrics;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
@@ -36,9 +35,10 @@ import org.sonar.core.metric.db.MetricDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.DbComponentsRefCache.DbComponent;
-import org.sonar.server.computation.language.LanguageRepository;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.server.measure.persistence.MeasureDao;
import org.sonar.server.metric.persistence.MetricDao;
@@ -46,7 +46,6 @@ import org.sonar.test.DbTests;
import static com.google.common.collect.Lists.newArrayList;
import static org.assertj.core.api.Assertions.assertThat;
-import static org.mockito.Mockito.mock;
@Category(DbTests.class)
public class PersistDuplicationsStepTest extends BaseStepTest {
@@ -59,14 +58,14 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
- DbSession session;
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
- DbClient dbClient;
+ DbIdsRepository dbIdsRepository = new DbIdsRepository();
- Settings projectSettings;
- LanguageRepository languageRepository;
+ DbSession session;
- DbComponentsRefCache dbComponentsRefCache;
+ DbClient dbClient;
PersistDuplicationsStep sut;
@@ -76,10 +75,7 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
session = dbTester.myBatis().openSession(false);
dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MeasureDao(), new MetricDao());
- projectSettings = new Settings();
- dbComponentsRefCache = new DbComponentsRefCache();
- languageRepository = mock(LanguageRepository.class);
- sut = new PersistDuplicationsStep(dbClient, dbComponentsRefCache, reportReader);
+ sut = new PersistDuplicationsStep(dbClient, dbIdsRepository, treeRootHolder, reportReader);
}
@Override
@@ -135,16 +131,18 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
@Test
public void persist_duplications_on_same_file_linked_on_a_module() throws Exception {
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
- dbComponentsRefCache.addComponent(2, new DbComponent(2L, "MODULE_KEY", "BCDE"));
- dbComponentsRefCache.addComponent(3, new DbComponent(3L, "MODULE_KEY:file", "CDEF"));
+ Component file = new DumbComponent(Component.Type.FILE, 3, "CDEF", "MODULE_KEY:file");
+ Component module = new DumbComponent(Component.Type.MODULE, 2, "BCDE", "MODULE_KEY", file);
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, module);
+ treeRootHolder.setRoot(project);
- saveDuplicationMetric();
+ dbIdsRepository.setComponentId(project, 1);
+ dbIdsRepository.setComponentId(module, 3);
+ dbIdsRepository.setComponentId(file, 2);
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
+ saveDuplicationMetric();
+ // TODO remove this when snapshot id will come from the DbIdsRepo
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -192,17 +190,18 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
@Test
public void persist_duplications_on_same_file_linked_on_a_folder() {
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
- dbComponentsRefCache.addComponent(2, new DbComponent(2L, "PROJECT_KEY:dir", "BCDE"));
- dbComponentsRefCache.addComponent(3, new DbComponent(3L, "PROJECT_KEY:file", "CDEF"));
+ Component file = new DumbComponent(Component.Type.FILE, 3, "CDEF", "PROJECT_KEY:file");
+ Component directory = new DumbComponent(Component.Type.DIRECTORY, 2, "BCDE", "PROJECT_KEY:dir", file);
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, directory);
+ treeRootHolder.setRoot(project);
+ dbIdsRepository.setComponentId(project, 1);
+ dbIdsRepository.setComponentId(directory, 3);
+ dbIdsRepository.setComponentId(file, 2);
saveDuplicationMetric();
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
-
+ // TODO remove this when snapshot id will come from the DbIdsRepo
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -250,17 +249,20 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
@Test
public void persist_duplications_on_same_file_linked_on_sub_folder() {
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
- dbComponentsRefCache.addComponent(2, new DbComponent(2L, "PROJECT_KEY:dir", "BCDE"));
- dbComponentsRefCache.addComponent(3, new DbComponent(3L, "PROJECT_KEY:dir", "CDEF"));
- dbComponentsRefCache.addComponent(10, new DbComponent(10L, "PROJECT_KEY:file", "DEFG"));
+ Component file = new DumbComponent(Component.Type.FILE, 10, "DEFG", "PROJECT_KEY:file");
+ Component directory1 = new DumbComponent(Component.Type.DIRECTORY, 3, "CDEF", "PROJECT_KEY:dir1", file);
+ Component directory2 = new DumbComponent(Component.Type.DIRECTORY, 2, "BCDE", "PROJECT_KEY:dir2", directory1);
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, directory2);
+ treeRootHolder.setRoot(project);
- saveDuplicationMetric();
+ dbIdsRepository.setComponentId(project, 1);
+ dbIdsRepository.setComponentId(directory1, 2);
+ dbIdsRepository.setComponentId(directory2, 3);
+ dbIdsRepository.setComponentId(file, 10);
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
+ saveDuplicationMetric();
+ // TODO remove this when snapshot id will come from the DbIdsRepo
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -314,10 +316,30 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
@Test
public void persist_duplications_on_different_files() {
- dbComponentsRefCache.addComponent(3, new DbComponent(3L, "PROJECT_KEY:file2", "CDEF"));
saveDuplicationMetric();
- initReportWithProjectAndFile();
+ Component file2 = new DumbComponent(Component.Type.FILE, 3, "CDEF", "PROJECT_KEY:file2");
+ Component file = new DumbComponent(Component.Type.FILE, 2, "BCDE", "PROJECT_KEY:file");
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, file, file2);
+ treeRootHolder.setRoot(project);
+
+ dbIdsRepository.setComponentId(project, 1);
+ dbIdsRepository.setComponentId(file, 2);
+
+ // TODO remove this when snapshot id will come from the DbIdsRepo
+ reportReader.putComponent(BatchReport.Component.newBuilder()
+ .setRef(1)
+ .setType(Constants.ComponentType.PROJECT)
+ .setKey(PROJECT_KEY)
+ .setSnapshotId(10L)
+ .addChildRef(2)
+ .build());
+ reportReader.putComponent(BatchReport.Component.newBuilder()
+ .setRef(2)
+ .setType(Constants.ComponentType.FILE)
+ .setSnapshotId(11L)
+ .setPath("file")
+ .build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(3)
.setType(Constants.ComponentType.FILE)
@@ -379,13 +401,14 @@ public class PersistDuplicationsStepTest extends BaseStepTest {
}
private void initReportWithProjectAndFile() {
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
- dbComponentsRefCache.addComponent(2, new DbComponent(2L, "PROJECT_KEY:file", "BCDE"));
+ Component file = new DumbComponent(Component.Type.FILE, 2, "BCDE", "PROJECT_KEY:file");
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, file);
+ treeRootHolder.setRoot(project);
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .build());
+ dbIdsRepository.setComponentId(project, 1);
+ dbIdsRepository.setComponentId(file, 2);
+ // TODO remove this when snapshot id will come from the DbIdsRepo
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java
index d2e0cef4d6c..d359abcec66 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistEventsStepTest.java
@@ -32,8 +32,9 @@ import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.DbComponentsRefCache.DbComponent;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.server.event.db.EventDao;
import org.sonar.test.DbTests;
@@ -44,15 +45,16 @@ import static org.mockito.Mockito.when;
@Category(DbTests.class)
public class PersistEventsStepTest extends BaseStepTest {
- private static final String PROJECT_KEY = "PROJECT_KEY";
-
@ClassRule
public static DbTester dbTester = new DbTester();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
DbSession session;
- DbComponentsRefCache dbComponentsRefCache;
PersistEventsStep step;
@Before
@@ -63,8 +65,7 @@ public class PersistEventsStepTest extends BaseStepTest {
System2 system2 = mock(System2.class);
when(system2.now()).thenReturn(1225630680000L);
- dbComponentsRefCache = new DbComponentsRefCache();
- step = new PersistEventsStep(dbClient, system2, dbComponentsRefCache, reportReader);
+ step = new PersistEventsStep(dbClient, system2, treeRootHolder, reportReader);
}
@Override
@@ -81,11 +82,10 @@ public class PersistEventsStepTest extends BaseStepTest {
public void nothing_to_do_when_no_events_in_report() throws Exception {
dbTester.prepareDbUnit(getClass(), "nothing_to_do_when_no_events_in_report.xml");
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
.setAnalysisDate(150000000L)
.build());
@@ -103,11 +103,10 @@ public class PersistEventsStepTest extends BaseStepTest {
public void persist_report_events() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
.setAnalysisDate(150000000L)
.build());
@@ -138,12 +137,11 @@ public class PersistEventsStepTest extends BaseStepTest {
public void persist_report_events_with_component_children() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
- dbComponentsRefCache.addComponent(2, new DbComponent(2L, "MODULE_KEY", "BCDE"));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null,
+ new DumbComponent(Component.Type.MODULE, 2, "BCDE", null)));
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
.setAnalysisDate(150000000L)
.build());
@@ -179,11 +177,10 @@ public class PersistEventsStepTest extends BaseStepTest {
public void create_version_event() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
.setAnalysisDate(150000000L)
.build());
@@ -203,11 +200,10 @@ public class PersistEventsStepTest extends BaseStepTest {
public void keep_one_event_by_version() throws Exception {
dbTester.prepareDbUnit(getClass(), "keep_one_event_by_version.xml");
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, PROJECT_KEY, "ABCD"));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
.setAnalysisDate(150000000L)
.build());
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java
index fd140226a40..355b1b5dd9d 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistFileSourcesStepTest.java
@@ -39,7 +39,9 @@ import org.sonar.core.persistence.DbTester;
import org.sonar.core.source.db.FileSourceDto;
import org.sonar.core.source.db.FileSourceDto.Type;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.computation.language.LanguageRepository;
import org.sonar.server.db.DbClient;
import org.sonar.server.source.db.FileSourceDao;
@@ -63,6 +65,10 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
@ClassRule
public static DbTester dbTester = new DbTester();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
@@ -71,7 +77,6 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
DbSession session;
DbClient dbClient;
- DbComponentsRefCache dbComponentsRefCache;
PersistFileSourcesStep sut;
long now = 123456789L;
@@ -84,8 +89,7 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
System2 system2 = mock(System2.class);
when(system2.now()).thenReturn(now);
- dbComponentsRefCache = new DbComponentsRefCache();
- sut = new PersistFileSourcesStep(dbClient, system2, dbComponentsRefCache, reportReader);
+ sut = new PersistFileSourcesStep(dbClient, system2, treeRootHolder, reportReader);
}
@Override
@@ -124,13 +128,9 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
@Test
public void persist_last_line() throws Exception {
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, PROJECT_UUID));
- dbComponentsRefCache.addComponent(FILE_REF, new DbComponentsRefCache.DbComponent(2L, "PROJECT_KEY:file", FILE_UUID));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, PROJECT_UUID, PROJECT_KEY,
+ new DumbComponent(Component.Type.FILE, FILE_REF, FILE_UUID, "PROJECT_KEY:file")));
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -428,19 +428,14 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
sut.execute();
failBecauseExceptionWasNotThrown(IllegalStateException.class);
} catch (IllegalStateException e) {
- assertThat(e).hasMessage("Cannot persist sources of src/Foo.java").hasCauseInstanceOf(IllegalArgumentException.class);
+ assertThat(e).hasMessage("Cannot persist sources of MODULE_KEY:src/Foo.java").hasCauseInstanceOf(IllegalArgumentException.class);
}
}
private void initBasicReport(int numberOfLines) throws IOException {
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, PROJECT_UUID));
- dbComponentsRefCache.addComponent(2, new DbComponentsRefCache.DbComponent(2L, "MODULE_KEY", "MODULE"));
- dbComponentsRefCache.addComponent(FILE_REF, new DbComponentsRefCache.DbComponent(3L, "MODULE_KEY:src/Foo.java", FILE_UUID));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, PROJECT_UUID, PROJECT_KEY,
+ new DumbComponent(Component.Type.MODULE, 2, "MODULE", "MODULE_KEY",
+ new DumbComponent(Component.Type.FILE, FILE_REF, FILE_UUID, "MODULE_KEY:src/Foo.java"))));
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
@@ -455,7 +450,6 @@ public class PersistFileSourcesStepTest extends BaseStepTest {
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(FILE_REF)
.setType(Constants.ComponentType.FILE)
- .setPath("src/Foo.java")
.setLines(numberOfLines)
.build());
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java
index 3f056cd33fd..81ac6888078 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistMeasuresStepTest.java
@@ -45,7 +45,10 @@ import org.sonar.core.persistence.DbTester;
import org.sonar.core.rule.RuleDto;
import org.sonar.server.component.db.ComponentDao;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.computation.issue.RuleCache;
import org.sonar.server.computation.issue.RuleCacheLoader;
import org.sonar.server.computation.measure.MetricCache;
@@ -65,14 +68,21 @@ public class PersistMeasuresStepTest extends BaseStepTest {
private static final String METRIC_KEY = "metric-key";
private static final RuleKey RULE_KEY = RuleKey.of("repo", "rule-key");
+ private static final long FILE_COMPONENT_ID = 3L;
+ private static final long FILE_SNAPSHOT_ID = 3L;
+
@ClassRule
public static DbTester dbTester = new DbTester();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
DbClient dbClient;
DbSession session;
- DbComponentsRefCache dbComponentsRefCache;
+ DbIdsRepository dbIdsRepository = new DbIdsRepository();
MetricDto metric;
RuleDto rule;
@@ -82,8 +92,6 @@ public class PersistMeasuresStepTest extends BaseStepTest {
public void setUp() {
dbTester.truncateTables();
- dbComponentsRefCache = new DbComponentsRefCache();
-
dbClient = new DbClient(dbTester.database(), dbTester.myBatis(), new MeasureDao(), new ComponentDao(), new MetricDao(), new RuleDao(System2.INSTANCE));
session = dbClient.openSession(false);
@@ -97,7 +105,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
MetricCache metricCache = new MetricCache(dbClient);
session.commit();
- sut = new PersistMeasuresStep(dbClient, ruleCache, metricCache, dbComponentsRefCache, reportReader);
+ sut = new PersistMeasuresStep(dbClient, ruleCache, metricCache, dbIdsRepository, treeRootHolder, reportReader);
}
@After
@@ -107,8 +115,15 @@ public class PersistMeasuresStepTest extends BaseStepTest {
@Test
public void insert_measures_from_report() throws Exception {
- ComponentDto project = addComponent(1, "project-key");
- ComponentDto file = addComponent(2, "file-key");
+ ComponentDto projectDto = addComponent(1, "project-key");
+ ComponentDto fileDto = addComponent(2, "file-key");
+
+ Component file = new DumbComponent(Component.Type.FILE, 2, "CDEF", "MODULE_KEY:file");
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "ABCD", PROJECT_KEY, file);
+ treeRootHolder.setRoot(project);
+
+ dbIdsRepository.setComponentId(project, projectDto.getId());
+ dbIdsRepository.setComponentId(file, fileDto.getId());
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setAnalysisDate(new Date().getTime())
@@ -172,7 +187,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
Map<String, Object> dto = dtos.get(0);
assertThat(dto.get("snapshotId")).isNotNull();
- assertThat(dto.get("componentId")).isEqualTo(project.getId());
+ assertThat(dto.get("componentId")).isEqualTo(projectDto.getId());
assertThat(dto.get("metricId")).isEqualTo(metric.getId().longValue());
assertThat(dto.get("ruleId")).isEqualTo(rule.getId().longValue());
assertThat(dto.get("textValue")).isEqualTo("measure-data");
@@ -180,7 +195,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
dto = dtos.get(1);
assertThat(dto.get("snapshotId")).isNotNull();
- assertThat(dto.get("componentId")).isEqualTo(file.getId());
+ assertThat(dto.get("componentId")).isEqualTo(fileDto.getId());
assertThat(dto.get("metricId")).isEqualTo(metric.getId().longValue());
assertThat(dto.get("ruleId")).isEqualTo(rule.getId().longValue());
assertThat(dto.get("value")).isEqualTo(123.123d);
@@ -210,7 +225,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setPersonId(5432)
.build();
- MeasureDto measure = sut.toMeasureDto(batchMeasure, component);
+ MeasureDto measure = sut.toMeasureDto(batchMeasure, componentDto.getId(), FILE_SNAPSHOT_ID);
assertThat(measure).isEqualToComparingFieldByField(new MeasureDto()
.setComponentId(componentDto.getId())
@@ -241,11 +256,11 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- MeasureDto measure = sut.toMeasureDto(batchMeasure, component);
+ MeasureDto measure = sut.toMeasureDto(batchMeasure, componentDto.getId(), FILE_SNAPSHOT_ID);
assertThat(measure).isEqualToComparingFieldByField(new MeasureDto()
.setComponentId(componentDto.getId())
- .setSnapshotId(3L)
+ .setSnapshotId(FILE_SNAPSHOT_ID)
.setMetricId(metric.getId()));
}
@@ -260,7 +275,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- MeasureDto measure = sut.toMeasureDto(batchMeasure, component);
+ MeasureDto measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isEqualTo(1.0);
@@ -270,7 +285,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- measure = sut.toMeasureDto(batchMeasure, component);
+ measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isEqualTo(0.0);
@@ -279,7 +294,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- measure = sut.toMeasureDto(batchMeasure, component);
+ measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isNull();
}
@@ -295,7 +310,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- MeasureDto measure = sut.toMeasureDto(batchMeasure, component);
+ MeasureDto measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isEqualTo(3.2);
@@ -304,7 +319,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- measure = sut.toMeasureDto(batchMeasure, component);
+ measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isNull();
}
@@ -320,7 +335,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- MeasureDto measure = sut.toMeasureDto(batchMeasure, component);
+ MeasureDto measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isEqualTo(3.0);
@@ -329,7 +344,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- measure = sut.toMeasureDto(batchMeasure, component);
+ measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isNull();
}
@@ -345,7 +360,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- MeasureDto measure = sut.toMeasureDto(batchMeasure, component);
+ MeasureDto measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isEqualTo(3.0);
@@ -354,7 +369,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
.setMetricKey(METRIC_KEY)
.build();
- measure = sut.toMeasureDto(batchMeasure, component);
+ measure = sut.toMeasureDto(batchMeasure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
assertThat(measure.getValue()).isNull();
}
@@ -368,7 +383,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
BatchReport.Component component = defaultComponent()
.build();
addComponent(component.getRef(), "component-key");
- sut.toMeasureDto(measure, component);
+ sut.toMeasureDto(measure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
}
@Test(expected = IllegalStateException.class)
@@ -379,7 +394,7 @@ public class PersistMeasuresStepTest extends BaseStepTest {
BatchReport.Component component = defaultComponent()
.build();
addComponent(component.getRef(), "component-key");
- sut.toMeasureDto(measure, component);
+ sut.toMeasureDto(measure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
}
@Test(expected = IllegalStateException.class)
@@ -390,40 +405,19 @@ public class PersistMeasuresStepTest extends BaseStepTest {
BatchReport.Component component = defaultComponent()
.build();
addComponent(component.getRef(), "component-key");
- sut.toMeasureDto(measure, component);
- }
-
- private MeasureDto expectedFullMeasure() {
- return new MeasureDto()
- .setComponentId(2L)
- .setSnapshotId(3L)
- .setCharacteristicId(123456)
- .setPersonId(5432)
- .setValue(123.123d)
- .setVariation(1, 1.1d)
- .setVariation(2, 2.2d)
- .setVariation(3, 3.3d)
- .setVariation(4, 4.4d)
- .setVariation(5, 5.5d)
- .setAlertStatus("WARN")
- .setAlertText("Open issues > 0")
- .setDescription("measure-description")
- .setSeverity(Severity.CRITICAL)
- .setMetricId(metric.getId())
- .setRuleId(rule.getId());
+ sut.toMeasureDto(measure, FILE_COMPONENT_ID, FILE_SNAPSHOT_ID);
}
private BatchReport.Component.Builder defaultComponent() {
return BatchReport.Component.newBuilder()
.setRef(1)
- .setSnapshotId(3);
+ .setSnapshotId(FILE_SNAPSHOT_ID);
}
private ComponentDto addComponent(int ref, String key) {
ComponentDto componentDto = new ComponentDto().setKey(key).setUuid(Uuids.create());
dbClient.componentDao().insert(session, componentDto);
session.commit();
- dbComponentsRefCache.addComponent(ref, new DbComponentsRefCache.DbComponent(componentDto.getId(), key, componentDto.uuid()));
return componentDto;
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java
index 31496f7335d..ff51c4d33ef 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistNumberOfDaysSinceLastCommitStepTest.java
@@ -33,7 +33,9 @@ import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.core.metric.db.MetricDto;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.computation.language.LanguageRepository;
import org.sonar.server.computation.measure.MetricCache;
import org.sonar.server.db.DbClient;
@@ -48,6 +50,10 @@ public class PersistNumberOfDaysSinceLastCommitStepTest extends BaseStepTest {
@ClassRule
public static DbTester db = new DbTester();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
@@ -59,8 +65,6 @@ public class PersistNumberOfDaysSinceLastCommitStepTest extends BaseStepTest {
Settings projectSettings;
LanguageRepository languageRepository;
- DbComponentsRefCache dbComponentsRefCache;
-
@Before
public void setUp() throws Exception {
db.truncateTables();
@@ -70,9 +74,8 @@ public class PersistNumberOfDaysSinceLastCommitStepTest extends BaseStepTest {
projectSettings = new Settings();
languageRepository = mock(LanguageRepository.class);
when(metricCache.get(anyString())).thenReturn(new MetricDto().setId(10));
- dbComponentsRefCache = new DbComponentsRefCache();
- sut = new PersistNumberOfDaysSinceLastCommitStep(System2.INSTANCE, dbClient, sourceLineIndex, metricCache, dbComponentsRefCache, reportReader);
+ sut = new PersistNumberOfDaysSinceLastCommitStep(System2.INSTANCE, dbClient, sourceLineIndex, metricCache, treeRootHolder, reportReader);
}
@Override
@@ -120,25 +123,21 @@ public class PersistNumberOfDaysSinceLastCommitStepTest extends BaseStepTest {
}
private void initReportWithProjectAndFile() {
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, "PROJECT_KEY", "project-uuid"));
- dbComponentsRefCache.addComponent(2, new DbComponentsRefCache.DbComponent(2L, "PROJECT_KEY:file", "file-uuid"));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "project-uuid", null,
+ new DumbComponent(Component.Type.FILE, 2, "file-uuid", null)));
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
.setSnapshotId(1000)
.build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
- .setKey("PROJECT_KEY")
- .setSnapshotId(10L)
.addChildRef(2)
.build());
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(2)
.setType(Constants.ComponentType.FILE)
- .setSnapshotId(11L)
.build());
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistProjectLinksStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistProjectLinksStepTest.java
index 7f89e57ee36..a7ec2f5be22 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistProjectLinksStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistProjectLinksStepTest.java
@@ -34,7 +34,9 @@ import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
import org.sonar.server.component.db.ComponentLinkDao;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.test.DbTests;
@@ -46,15 +48,16 @@ import static org.mockito.Mockito.when;
@Category(DbTests.class)
public class PersistProjectLinksStepTest extends BaseStepTest {
- private static final String PROJECT_KEY = "PROJECT_KEY";
-
@ClassRule
public static DbTester dbTester = new DbTester();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
DbSession session;
- DbComponentsRefCache dbComponentsRefCache;
PersistProjectLinksStep step;
@@ -70,8 +73,7 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
when(i18n.message(Locale.ENGLISH, "project_links.ci", null)).thenReturn("Continuous integration");
when(i18n.message(Locale.ENGLISH, "project_links.issue", null)).thenReturn("Issues");
- dbComponentsRefCache = new DbComponentsRefCache();
- step = new PersistProjectLinksStep(dbClient, i18n, dbComponentsRefCache, reportReader);
+ step = new PersistProjectLinksStep(dbClient, i18n, treeRootHolder, reportReader);
}
@Override
@@ -88,16 +90,10 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
public void add_links_on_project_and_module() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
- dbComponentsRefCache.addComponent(2, new DbComponentsRefCache.DbComponent(2L, "MODULE_KEY", "BCDE"));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null,
+ new DumbComponent(Component.Type.MODULE, 2, "BCDE", null)));
// project and 1 module
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .setAnalysisDate(150000000L)
- .build());
-
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
.setType(Constants.ComponentType.PROJECT)
@@ -123,12 +119,7 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
public void nothing_to_do_when_link_already_exists() throws Exception {
dbTester.prepareDbUnit(getClass(), "nothing_to_do_when_link_already_exists.xml");
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
@@ -145,15 +136,16 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
public void do_not_add_links_on_file() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null,
+ new DumbComponent(Component.Type.FILE, 2, "BCDE", null)));
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
+ .setType(Constants.ComponentType.PROJECT)
+ .addChildRef(2)
+ .build());
+ reportReader.putComponent(BatchReport.Component.newBuilder()
+ .setRef(2)
.setType(Constants.ComponentType.FILE)
.addLink(BatchReport.ComponentLink.newBuilder().setType(Constants.ComponentLinkType.HOME).setHref("http://www.sonarqube.org").build())
.build());
@@ -167,12 +159,7 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
public void update_link() throws Exception {
dbTester.prepareDbUnit(getClass(), "update_link.xml");
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
@@ -189,12 +176,7 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
public void delete_link() throws Exception {
dbTester.prepareDbUnit(getClass(), "delete_link.xml");
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
@@ -210,12 +192,7 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
public void not_delete_custom_link() throws Exception {
dbTester.prepareDbUnit(getClass(), "not_delete_custom_link.xml");
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
@@ -231,12 +208,7 @@ public class PersistProjectLinksStepTest extends BaseStepTest {
public void fail_when_trying_to_add_same_link_type_multiple_times() throws Exception {
dbTester.prepareDbUnit(getClass(), "empty.xml");
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, "ABCD"));
-
- reportReader.setMetadata(BatchReport.Metadata.newBuilder()
- .setRootComponentRef(1)
- .setProjectKey(PROJECT_KEY)
- .build());
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, "ABCD", null));
reportReader.putComponent(BatchReport.Component.newBuilder()
.setRef(1)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistTestsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistTestsStepTest.java
index 31afd166b45..9306b3b0566 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistTestsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PersistTestsStepTest.java
@@ -40,8 +40,6 @@ import org.sonar.core.source.db.FileSourceDto;
import org.sonar.server.computation.batch.BatchReportReaderRule;
import org.sonar.server.computation.batch.TreeRootHolderRule;
import org.sonar.server.computation.component.Component;
-import org.sonar.server.computation.component.DbComponentsRefCache;
-import org.sonar.server.computation.component.DbComponentsRefCache.DbComponent;
import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.db.DbClient;
import org.sonar.server.source.db.FileSourceDao;
@@ -53,6 +51,7 @@ import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
public class PersistTestsStepTest extends BaseStepTest {
+
private static final String PROJECT_UUID = "PROJECT";
private static final String PROJECT_KEY = "PROJECT_KEY";
private static final int TEST_FILE_REF_1 = 3;
@@ -68,16 +67,18 @@ public class PersistTestsStepTest extends BaseStepTest {
@ClassRule
public static DbTester db = new DbTester();
+
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
@Rule
public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public LogTester log = new LogTester();
DbSession session;
DbClient dbClient;
- DbComponentsRefCache dbComponentsRefCache;
Component root;
PersistTestsStep sut;
@@ -93,8 +94,7 @@ public class PersistTestsStepTest extends BaseStepTest {
System2 system2 = mock(System2.class);
when(system2.now()).thenReturn(now);
- dbComponentsRefCache = new DbComponentsRefCache();
- sut = new PersistTestsStep(dbClient, system2, dbComponentsRefCache, reportReader, treeRootHolder);
+ sut = new PersistTestsStep(dbClient, system2, reportReader, treeRootHolder);
initBasicReport();
@@ -218,8 +218,8 @@ public class PersistTestsStepTest extends BaseStepTest {
public void aggregate_coverage_details() {
reportReader.putTests(TEST_FILE_REF_1, Arrays.asList(newTest(1)));
reportReader.putCoverageDetails(TEST_FILE_REF_1, Arrays.asList(
- newCoverageDetailWithLines(1, MAIN_FILE_REF_1, 1, 3),
- newCoverageDetailWithLines(1, MAIN_FILE_REF_1, 2, 4)));
+ newCoverageDetailWithLines(1, MAIN_FILE_REF_1, 1, 3),
+ newCoverageDetailWithLines(1, MAIN_FILE_REF_1, 2, 4)));
sut.execute();
@@ -300,13 +300,6 @@ public class PersistTestsStepTest extends BaseStepTest {
}
private void initBasicReport() {
- dbComponentsRefCache.addComponent(1, new DbComponent(1L, "PROJECT_KEY", PROJECT_UUID));
- dbComponentsRefCache.addComponent(2, new DbComponent(2L, "MODULE_KEY", "MODULE"));
- dbComponentsRefCache.addComponent(3, new DbComponent(3L, "TEST_FILE1_KEY", TEST_FILE_UUID_1));
- dbComponentsRefCache.addComponent(4, new DbComponent(4L, "TEST_FILE2_KEY", TEST_FILE_UUID_2));
- dbComponentsRefCache.addComponent(5, new DbComponent(5L, "MAIN_FILE1_KEY", MAIN_FILE_UUID_1));
- dbComponentsRefCache.addComponent(6, new DbComponent(6L, "MAIN_FILE2_KEY", MAIN_FILE_UUID_2));
-
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
.setProjectKey(PROJECT_KEY)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java
index 3852abbb4df..38925d25ed5 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/PurgeDatastoresStepTest.java
@@ -32,7 +32,10 @@ import org.sonar.core.computation.dbcleaner.ProjectCleaner;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.purge.IdUuidPair;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DbIdsRepository;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.computation.component.ProjectSettingsRepository;
import org.sonar.server.db.DbClient;
@@ -49,11 +52,15 @@ public class PurgeDatastoresStepTest extends BaseStepTest {
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
+ DbIdsRepository dbIdsRepository = new DbIdsRepository();
+
ProjectCleaner projectCleaner = mock(ProjectCleaner.class);
- DbComponentsRefCache dbComponentsRefCache = new DbComponentsRefCache();
ProjectSettingsRepository projectSettingsRepository = mock(ProjectSettingsRepository.class);
- PurgeDatastoresStep sut = new PurgeDatastoresStep(mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS), projectCleaner, dbComponentsRefCache, projectSettingsRepository, reportReader);
+ PurgeDatastoresStep sut = new PurgeDatastoresStep(mock(DbClient.class, Mockito.RETURNS_DEEP_STUBS), projectCleaner, dbIdsRepository, treeRootHolder, projectSettingsRepository);
@Before
public void setUp() throws Exception {
@@ -62,7 +69,9 @@ public class PurgeDatastoresStepTest extends BaseStepTest {
@Test
public void call_purge_method_of_the_purge_task() throws IOException {
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(123L, PROJECT_KEY, "UUID-1234"));
+ Component project = new DumbComponent(Component.Type.PROJECT, 1, "UUID-1234", PROJECT_KEY);
+ treeRootHolder.setRoot(project);
+ dbIdsRepository.setComponentId(project, 123L);
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
diff --git a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java
index cf1ca6f6a36..7fb81786e6c 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/computation/step/SendIssueNotificationsStepTest.java
@@ -32,7 +32,9 @@ import org.sonar.api.utils.System2;
import org.sonar.batch.protocol.Constants;
import org.sonar.batch.protocol.output.BatchReport;
import org.sonar.server.computation.batch.BatchReportReaderRule;
-import org.sonar.server.computation.component.DbComponentsRefCache;
+import org.sonar.server.computation.batch.TreeRootHolderRule;
+import org.sonar.server.computation.component.Component;
+import org.sonar.server.computation.component.DumbComponent;
import org.sonar.server.computation.issue.IssueCache;
import org.sonar.server.computation.issue.RuleCache;
import org.sonar.server.issue.notification.IssueChangeNotification;
@@ -54,6 +56,10 @@ public class SendIssueNotificationsStepTest extends BaseStepTest {
@Rule
public BatchReportReaderRule reportReader = new BatchReportReaderRule();
+
+ @Rule
+ public TreeRootHolderRule treeRootHolder = new TreeRootHolderRule();
+
@Rule
public TemporaryFolder temp = new TemporaryFolder();
@@ -64,11 +70,10 @@ public class SendIssueNotificationsStepTest extends BaseStepTest {
@Before
public void setUp() throws Exception {
issueCache = new IssueCache(temp.newFile(), System2.INSTANCE);
- DbComponentsRefCache dbComponentsRefCache = new DbComponentsRefCache();
NewIssuesNotificationFactory newIssuesNotificationFactory = mock(NewIssuesNotificationFactory.class, Mockito.RETURNS_DEEP_STUBS);
- sut = new SendIssueNotificationsStep(issueCache, mock(RuleCache.class), dbComponentsRefCache, notifService, reportReader, newIssuesNotificationFactory);
+ sut = new SendIssueNotificationsStep(issueCache, mock(RuleCache.class), treeRootHolder, notifService, reportReader, newIssuesNotificationFactory);
- dbComponentsRefCache.addComponent(1, new DbComponentsRefCache.DbComponent(1L, PROJECT_KEY, PROJECT_UUID));
+ treeRootHolder.setRoot(new DumbComponent(Component.Type.PROJECT, 1, PROJECT_UUID, PROJECT_KEY));
reportReader.setMetadata(BatchReport.Metadata.newBuilder()
.setRootComponentRef(1)
@@ -93,7 +98,7 @@ public class SendIssueNotificationsStepTest extends BaseStepTest {
@Test
public void send_notifications_if_subscribers() {
issueCache.newAppender().append(new DefaultIssue()
- .setSeverity(Severity.BLOCKER)).close();
+ .setSeverity(Severity.BLOCKER)).close();
when(notifService.hasProjectSubscribersForTypes(PROJECT_UUID, SendIssueNotificationsStep.NOTIF_TYPES)).thenReturn(true);
diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/MigrationStepModuleTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/MigrationStepModuleTest.java
index b0522568bed..abc50e78e77 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/MigrationStepModuleTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/MigrationStepModuleTest.java
@@ -29,6 +29,6 @@ public class MigrationStepModuleTest {
public void verify_count_of_added_MigrationStep_types() throws Exception {
ComponentContainer container = new ComponentContainer();
new MigrationStepModule().configure(container);
- assertThat(container.size()).isEqualTo(54);
+ assertThat(container.size()).isEqualTo(55);
}
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest.java b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest.java
new file mode 100644
index 00000000000..aac8b55a99b
--- /dev/null
+++ b/server/sonar-server/src/test/java/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest.java
@@ -0,0 +1,53 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package org.sonar.server.db.migrations.v52;
+
+import org.junit.Before;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.sonar.core.persistence.DbTester;
+import org.sonar.server.db.migrations.MigrationStep;
+
+public class FeedMetricsBooleansTest {
+ @ClassRule
+ public static DbTester db = new DbTester().schema(FeedMetricsBooleansTest.class, "schema.sql");
+
+ MigrationStep migration;
+
+ @Before
+ public void setUp() {
+ db.executeUpdateSql("truncate table metrics");
+
+ migration = new FeedMetricsBooleans(db.database());
+ }
+
+ @Test
+ public void migrate_empty_db() throws Exception {
+ migration.execute();
+ }
+
+ @Test
+ public void migrate() throws Exception {
+ db.prepareDbUnit(this.getClass(), "migrate.xml");
+ migration.execute();
+ db.assertDbUnit(this.getClass(), "migrate-result.xml", "metrics");
+ }
+}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java b/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java
index 1f77cf7c866..8fae20fa06a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/metric/persistence/MetricDaoTest.java
@@ -28,6 +28,7 @@ import org.junit.experimental.categories.Category;
import org.sonar.core.metric.db.MetricDto;
import org.sonar.core.persistence.DbSession;
import org.sonar.core.persistence.DbTester;
+import org.sonar.server.exceptions.NotFoundException;
import org.sonar.test.DbTests;
import static org.assertj.core.api.Assertions.assertThat;
@@ -82,6 +83,11 @@ public class MetricDaoTest {
assertThat(result.isEnabled()).isFalse();
}
+ @Test(expected = NotFoundException.class)
+ public void get_nullable_by_key() {
+ dao.selectByKey(session, "unknown");
+ }
+
@Test
public void get_manual_metric() {
dbTester.prepareDbUnit(getClass(), "manual_metric.xml");
@@ -99,9 +105,9 @@ public class MetricDaoTest {
assertThat(result.isUserManaged()).isTrue();
assertThat(result.getWorstValue()).isNull();
assertThat(result.getBestValue()).isNull();
- assertThat(result.isOptimizedBestValue()).isNull();
- assertThat(result.isDeleteHistoricalData()).isNull();
- assertThat(result.isHidden()).isNull();
+ assertThat(result.isOptimizedBestValue()).isFalse();
+ assertThat(result.isDeleteHistoricalData()).isFalse();
+ assertThat(result.isHidden()).isFalse();
assertThat(result.isEnabled()).isTrue();
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java
index 03682b2ffdb..8d28df8418a 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/plugins/ws/AbstractUpdateCenterBasedPluginsWsActionTest.java
@@ -38,7 +38,7 @@ import static org.mockito.Mockito.when;
import static org.sonar.updatecenter.common.PluginUpdate.Status.COMPATIBLE;
import static org.sonar.updatecenter.common.Version.create;
-public class AbstractUpdateCenterBasedPluginsWsActionTest {
+public abstract class AbstractUpdateCenterBasedPluginsWsActionTest {
protected static final String DUMMY_CONTROLLER_KEY = "dummy";
protected static final String JSON_EMPTY_PLUGIN_LIST =
"{" +
diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java
index c447745f4e0..40385f5e2e6 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/BulkDeleteActionTest.java
@@ -76,7 +76,7 @@ import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.project.ws.BulkDeleteAction.PARAM_KEYS;
-import static org.sonar.server.project.ws.BulkDeleteAction.PARAM_UUIDS;
+import static org.sonar.server.project.ws.BulkDeleteAction.PARAM_IDS;
@Category(DbTests.class)
public class BulkDeleteActionTest {
@@ -127,7 +127,7 @@ public class BulkDeleteActionTest {
long snapshotId4 = insertNewProjectInDbAndReturnSnapshotId(4);
ws.newPostRequest("api/projects", ACTION)
- .setParam(PARAM_UUIDS, "project-uuid-1, project-uuid-3, project-uuid-4").execute();
+ .setParam(PARAM_IDS, "project-uuid-1, project-uuid-3, project-uuid-4").execute();
dbSession.commit();
assertThat(dbClient.componentDao().selectByUuids(dbSession, Arrays.asList("project-uuid-1", "project-uuid-3", "project-uuid-4"))).isEmpty();
@@ -180,7 +180,7 @@ public class BulkDeleteActionTest {
public void web_service_returns_204() throws Exception {
insertNewProjectInDbAndReturnSnapshotId(1);
- WsTester.Result result = ws.newPostRequest("api/projects", ACTION).setParam(PARAM_UUIDS, "project-uuid-1").execute();
+ WsTester.Result result = ws.newPostRequest("api/projects", ACTION).setParam(PARAM_IDS, "project-uuid-1").execute();
result.assertNoContent();
}
@@ -190,7 +190,7 @@ public class BulkDeleteActionTest {
userSessionRule.setGlobalPermissions(UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN, UserRole.USER);
expectedException.expect(ForbiddenException.class);
- ws.newPostRequest("api/projects", ACTION).setParam(PARAM_UUIDS, "whatever-the-uuid").execute();
+ ws.newPostRequest("api/projects", ACTION).setParam(PARAM_IDS, "whatever-the-uuid").execute();
}
@Test
@@ -199,7 +199,7 @@ public class BulkDeleteActionTest {
dbClient.componentDao().insert(dbSession, ComponentTesting.newFileDto(ComponentTesting.newProjectDto(), "file-uuid"));
dbSession.commit();
- ws.newPostRequest("api/projects", ACTION).setParam(PARAM_UUIDS, "file-uuid").execute();
+ ws.newPostRequest("api/projects", ACTION).setParam(PARAM_IDS, "file-uuid").execute();
}
@Test
@@ -209,7 +209,7 @@ public class BulkDeleteActionTest {
dbSession.commit();
when(resourceType.getBooleanProperty(anyString())).thenReturn(false);
- ws.newPostRequest("api/projects", ACTION).setParam(PARAM_UUIDS, "project-uuid").execute();
+ ws.newPostRequest("api/projects", ACTION).setParam(PARAM_IDS, "project-uuid").execute();
}
private long insertNewProjectInDbAndReturnSnapshotId(int id) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java
index 37d48248a46..404e52eba11 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/project/ws/DeleteActionTest.java
@@ -74,7 +74,7 @@ import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import static org.sonar.server.project.ws.DeleteAction.PARAM_KEY;
-import static org.sonar.server.project.ws.DeleteAction.PARAM_UUID;
+import static org.sonar.server.project.ws.DeleteAction.PARAM_ID;
@Category(DbTests.class)
public class DeleteActionTest {
@@ -123,7 +123,7 @@ public class DeleteActionTest {
long snapshotId2 = insertNewProjectInDbAndReturnSnapshotId(2);
newRequest()
- .setParam(PARAM_UUID, "project-uuid-1").execute();
+ .setParam(PARAM_ID, "project-uuid-1").execute();
dbSession.commit();
assertThat(dbClient.componentDao().selectNullableByUuid(dbSession, "project-uuid-1")).isNull();
@@ -152,7 +152,7 @@ public class DeleteActionTest {
insertNewProjectInDbAndReturnSnapshotId(1);
userSessionRule.login("login").addProjectUuidPermissions(UserRole.ADMIN, "project-uuid-1");
- newRequest().setParam(PARAM_UUID, "project-uuid-1").execute();
+ newRequest().setParam(PARAM_ID, "project-uuid-1").execute();
dbSession.commit();
assertThat(dbClient.componentDao().selectNullableByUuid(dbSession, "project-uuid-1")).isNull();
@@ -193,7 +193,7 @@ public class DeleteActionTest {
public void web_service_returns_204() throws Exception {
insertNewProjectInDbAndReturnSnapshotId(1);
- WsTester.Result result = newRequest().setParam(PARAM_UUID, "project-uuid-1").execute();
+ WsTester.Result result = newRequest().setParam(PARAM_ID, "project-uuid-1").execute();
result.assertNoContent();
}
@@ -203,7 +203,7 @@ public class DeleteActionTest {
userSessionRule.setGlobalPermissions(UserRole.CODEVIEWER, UserRole.ISSUE_ADMIN, UserRole.USER);
expectedException.expect(ForbiddenException.class);
- newRequest().setParam(PARAM_UUID, "whatever-the-uuid").execute();
+ newRequest().setParam(PARAM_ID, "whatever-the-uuid").execute();
}
@Test
@@ -212,7 +212,7 @@ public class DeleteActionTest {
dbClient.componentDao().insert(dbSession, ComponentTesting.newFileDto(ComponentTesting.newProjectDto(), "file-uuid"));
dbSession.commit();
- newRequest().setParam(PARAM_UUID, "file-uuid").execute();
+ newRequest().setParam(PARAM_ID, "file-uuid").execute();
}
@Test
@@ -222,7 +222,7 @@ public class DeleteActionTest {
dbSession.commit();
when(resourceType.getBooleanProperty(anyString())).thenReturn(false);
- newRequest().setParam(PARAM_UUID, "project-uuid").execute();
+ newRequest().setParam(PARAM_ID, "project-uuid").execute();
}
private long insertNewProjectInDbAndReturnSnapshotId(int id) {
diff --git a/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java
index c35d5cb0a06..d57b5baa082 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/user/ws/GroupsActionTest.java
@@ -26,6 +26,7 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.server.ws.WebService.SelectionMode;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.DbSession;
@@ -111,6 +112,7 @@ public class GroupsActionTest {
tester.newGetRequest("api/users", "groups")
.setParam("login", "john")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all.json");
}
@@ -125,7 +127,12 @@ public class GroupsActionTest {
tester.newGetRequest("api/users", "groups")
.setParam("login", "john")
- .setParam("selected", "selected")
+ .execute()
+ .assertJson(getClass(), "selected.json");
+
+ tester.newGetRequest("api/users", "groups")
+ .setParam("login", "john")
+ .setParam(Param.SELECTED, SelectionMode.SELECTED.value())
.execute()
.assertJson(getClass(), "selected.json");
}
@@ -140,7 +147,7 @@ public class GroupsActionTest {
tester.newGetRequest("api/users", "groups")
.setParam("login", "john")
- .setParam("selected", "deselected")
+ .setParam(Param.SELECTED, SelectionMode.DESELECTED.value())
.execute()
.assertJson(getClass(), "deselected.json");
}
@@ -165,6 +172,7 @@ public class GroupsActionTest {
tester.newGetRequest("api/users", "groups")
.setParam("login", "john")
.setParam(Param.PAGE_SIZE, "1")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all_page1.json");
@@ -172,6 +180,7 @@ public class GroupsActionTest {
.setParam("login", "john")
.setParam(Param.PAGE_SIZE, "1")
.setParam(Param.PAGE, "2")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all_page2.json");
}
@@ -187,12 +196,14 @@ public class GroupsActionTest {
tester.newGetRequest("api/users", "groups")
.setParam("login", "john")
.setParam("q", "users")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all_users.json");
tester.newGetRequest("api/users", "groups")
.setParam("login", "john")
.setParam("q", "admin")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all_admin.json");
}
diff --git a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java
index 30c31d346cc..c7288d6d818 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/usergroups/ws/UsersActionTest.java
@@ -26,6 +26,8 @@ import org.junit.ClassRule;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
+import org.sonar.api.server.ws.WebService.Param;
+import org.sonar.api.server.ws.WebService.SelectionMode;
import org.sonar.api.utils.System2;
import org.sonar.core.permission.GlobalPermissions;
import org.sonar.core.persistence.DbSession;
@@ -122,6 +124,7 @@ public class UsersActionTest {
newUsersRequest()
.setParam("id", group.getId().toString())
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all.json");
}
@@ -136,7 +139,12 @@ public class UsersActionTest {
newUsersRequest()
.setParam("id", group.getId().toString())
- .setParam("selected", "selected")
+ .execute()
+ .assertJson(getClass(), "selected.json");
+
+ newUsersRequest()
+ .setParam("id", group.getId().toString())
+ .setParam(Param.SELECTED, SelectionMode.SELECTED.value())
.execute()
.assertJson(getClass(), "selected.json");
}
@@ -151,7 +159,7 @@ public class UsersActionTest {
newUsersRequest()
.setParam("id", group.getId().toString())
- .setParam("selected", "deselected")
+ .setParam(Param.SELECTED, SelectionMode.DESELECTED.value())
.execute()
.assertJson(getClass(), "deselected.json");
}
@@ -167,6 +175,7 @@ public class UsersActionTest {
newUsersRequest()
.setParam("id", group.getId().toString())
.setParam("ps", "1")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all_page1.json");
@@ -174,6 +183,7 @@ public class UsersActionTest {
.setParam("id", group.getId().toString())
.setParam("ps", "1")
.setParam("p", "2")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all_page2.json");
}
@@ -189,6 +199,7 @@ public class UsersActionTest {
newUsersRequest()
.setParam("id", group.getId().toString())
.setParam("q", "ace")
+ .setParam(Param.SELECTED, SelectionMode.ALL.value())
.execute()
.assertJson(getClass(), "all.json");
diff --git a/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java b/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java
index 83f06bf385b..057e5975c3b 100644
--- a/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java
+++ b/server/sonar-server/src/test/java/org/sonar/server/util/CloseableIteratorTest.java
@@ -19,7 +19,9 @@
*/
package org.sonar.server.util;
+import java.io.IOException;
import java.util.Collections;
+import java.util.Iterator;
import java.util.NoSuchElementException;
import org.junit.Test;
@@ -117,7 +119,7 @@ public class CloseableIteratorTest {
}
@Test(expected = NoSuchElementException.class)
- public void emptyIterator_next_throws_NoSuchElemetException() {
+ public void emptyIterator_next_throws_NoSuchElementException() {
CloseableIterator.emptyCloseableIterator().next();
}
@@ -131,6 +133,35 @@ public class CloseableIteratorTest {
CloseableIterator.from(new SimpleCloseableIterator());
}
+ @Test(expected = IllegalArgumentException.class)
+ public void from_iterator_throws_IAE_if_arg_is_a_AutoCloseable() {
+ CloseableIterator.from(new CloseableIt());
+ }
+
+ private static class CloseableIt implements Iterator<String>, AutoCloseable {
+ private final Iterator<String> delegate = Collections.<String>emptyList().iterator();
+
+ @Override
+ public void remove() {
+ delegate.remove();
+ }
+
+ @Override
+ public String next() {
+ return delegate.next();
+ }
+
+ @Override
+ public boolean hasNext() {
+ return delegate.hasNext();
+ }
+
+ @Override
+ public void close() throws IOException {
+ // no need to implement it for real
+ }
+ }
+
@Test
public void verify_has_next_from_iterator_with_empty_iterator() {
assertThat(CloseableIterator.from(Collections.<String>emptyList().iterator()).hasNext()).isFalse();
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate-result.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate-result.xml
new file mode 100644
index 00000000000..026d2dbe83a
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate-result.xml
@@ -0,0 +1,7 @@
+<dataset>
+
+ <metrics id="1" user_managed="[true]" optimized_best_value="[false]" hidden="[false]" delete_historical_data="[false]" />
+ <metrics id="2" user_managed="[false]" optimized_best_value="[true]" hidden="[true]" delete_historical_data="[true]" />
+ <metrics id="3" user_managed="[false]" optimized_best_value="[false]" hidden="[false]" delete_historical_data="[false]"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate.xml b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate.xml
new file mode 100644
index 00000000000..7fee0be9b77
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/migrate.xml
@@ -0,0 +1,7 @@
+<dataset>
+
+ <metrics id="1" user_managed="[true]" optimized_best_value="[null]" hidden="[null]" delete_historical_data="[null]"/>
+ <metrics id="2" user_managed="[false]" optimized_best_value="[true]" hidden="[true]" delete_historical_data="[true]"/>
+ <metrics id="3" user_managed="[false]" optimized_best_value="[null]" hidden="[null]" delete_historical_data="[null]"/>
+
+</dataset>
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/schema.sql b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/schema.sql
new file mode 100644
index 00000000000..d65487d7677
--- /dev/null
+++ b/server/sonar-server/src/test/resources/org/sonar/server/db/migrations/v52/FeedMetricsBooleansTest/schema.sql
@@ -0,0 +1,7 @@
+CREATE TABLE "METRICS" (
+ "ID" INTEGER NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1),
+ "USER_MANAGED" BOOLEAN DEFAULT FALSE,
+ "OPTIMIZED_BEST_VALUE" BOOLEAN,
+ "HIDDEN" BOOLEAN,
+ "DELETE_HISTORICAL_DATA" BOOLEAN
+);
diff --git a/server/sonar-server/src/test/resources/org/sonar/server/metric/persistence/MetricDaoTest/manual_metric.xml b/server/sonar-server/src/test/resources/org/sonar/server/metric/persistence/MetricDaoTest/manual_metric.xml
index 630722c4d75..8dc260a5fae 100644
--- a/server/sonar-server/src/test/resources/org/sonar/server/metric/persistence/MetricDaoTest/manual_metric.xml
+++ b/server/sonar-server/src/test/resources/org/sonar/server/metric/persistence/MetricDaoTest/manual_metric.xml
@@ -1,7 +1,7 @@
<dataset>
<metrics id="1" name="manual" val_type="INT" description="Manual metric" domain="" short_name="Manual metric"
- qualitative="[false]" enabled="[true]" worst_value="[null]" optimized_best_value="[null]" best_value="[null]" direction="0" hidden="[null]"
- origin="GUI" delete_historical_data="[null]" user_managed="[true]"/>
+ qualitative="[false]" enabled="[true]" worst_value="[null]" optimized_best_value="[false]" best_value="[null]" direction="0" hidden="[false]"
+ origin="GUI" delete_historical_data="[false]" user_managed="[true]"/>
</dataset>
diff --git a/server/sonar-web/Gruntfile.coffee b/server/sonar-web/Gruntfile.coffee
index ff402d13cb0..7375822b38e 100644
--- a/server/sonar-web/Gruntfile.coffee
+++ b/server/sonar-web/Gruntfile.coffee
@@ -46,6 +46,7 @@ module.exports = (grunt) ->
'<%= BUILD_PATH %>/js/libs/third-party/latinize.js'
'<%= BUILD_PATH %>/js/libs/third-party/underscore.js'
'<%= BUILD_PATH %>/js/libs/third-party/backbone.js'
+ '<%= BUILD_PATH %>/js/libs/third-party/backbone-super.js'
'<%= BUILD_PATH %>/js/libs/third-party/backbone.marionette.js'
'<%= BUILD_PATH %>/js/libs/third-party/handlebars.js'
'<%= BUILD_PATH %>/js/libs/third-party/underscore.js'
@@ -123,6 +124,7 @@ module.exports = (grunt) ->
'build-app:coding-rules'
'build-app:computation'
'build-app:drilldown'
+ 'build-app:groups'
'build-app:markdown'
'build-app:measures'
'build-app:nav'
@@ -156,6 +158,7 @@ module.exports = (grunt) ->
'casper:ui'
'casper:workspace'
'casper:users'
+ 'casper:groups'
'casper:provisioning'
'casper:computation'
]
@@ -215,6 +218,9 @@ module.exports = (grunt) ->
'<%= BUILD_PATH %>/js/apps/users/templates.js': [
'<%= SOURCE_PATH %>/js/apps/users/templates/**/*.hbs'
]
+ '<%= BUILD_PATH %>/js/apps/groups/templates.js': [
+ '<%= SOURCE_PATH %>/js/apps/groups/templates/**/*.hbs'
+ ]
'<%= BUILD_PATH %>/js/apps/provisioning/templates.js': [
'<%= SOURCE_PATH %>/js/apps/provisioning/templates/**/*.hbs'
]
@@ -319,6 +325,8 @@ module.exports = (grunt) ->
src: ['src/test/js/provisioning*.js']
computation:
src: ['src/test/js/computation*.js']
+ groups:
+ src: ['src/test/js/groups-spec.js']
uglify:
build:
diff --git a/server/sonar-web/pom.xml b/server/sonar-web/pom.xml
index 857e044aa93..5203f26cf38 100644
--- a/server/sonar-web/pom.xml
+++ b/server/sonar-web/pom.xml
@@ -16,6 +16,7 @@
<sonar.sources>src/main/js,src/main/less</sonar.sources>
<sonar.exclusions>src/main/js/libs/third-party/**/*,src/main/js/libs/require.js</sonar.exclusions>
<sonar.javascript.lcov.reportPath>target/js-coverage/lcov.info</sonar.javascript.lcov.reportPath>
+ <grunt.arguments>maven-build-skip-tests-${skipWebTests}-${jsCoverage} --port=${jsTestPort} --no-color</grunt.arguments>
</properties>
<build>
@@ -130,7 +131,7 @@
<goal>grunt</goal>
</goals>
<configuration>
- <arguments>maven-build-skip-tests-${skipWebTests}-${jsCoverage} --port=${jsTestPort} --no-color</arguments>
+ <arguments>${grunt.arguments}</arguments>
</configuration>
</execution>
</executions>
@@ -201,6 +202,12 @@
</dependency>
</dependencies>
</profile>
+ <profile>
+ <id>dev</id>
+ <properties>
+ <grunt.arguments>maven-quick-build</grunt.arguments>
+ </properties>
+ </profile>
</profiles>
</project>
diff --git a/server/sonar-web/src/main/js/apps/groups/app.js b/server/sonar-web/src/main/js/apps/groups/app.js
new file mode 100644
index 00000000000..55c6dfef534
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/app.js
@@ -0,0 +1,47 @@
+define([
+ './layout',
+ './groups',
+ './header-view',
+ './search-view',
+ './list-view',
+ './list-footer-view'
+], function (Layout, Groups, HeaderView, SearchView, ListView, ListFooterView) {
+
+ var App = new Marionette.Application(),
+ init = function (options) {
+ // Layout
+ this.layout = new Layout({ el: options.el });
+ this.layout.render();
+
+ // Collection
+ this.groups = new Groups();
+
+ // Header View
+ this.headerView = new HeaderView({ collection: this.groups });
+ this.layout.headerRegion.show(this.headerView);
+
+ // Search View
+ this.searchView = new SearchView({ collection: this.groups });
+ this.layout.searchRegion.show(this.searchView);
+
+ // List View
+ this.listView = new ListView({ collection: this.groups });
+ this.layout.listRegion.show(this.listView);
+
+ // List Footer View
+ this.listFooterView = new ListFooterView({ collection: this.groups });
+ this.layout.listFooterRegion.show(this.listFooterView);
+
+ // Go!
+ this.groups.fetch();
+ };
+
+ App.on('start', function (options) {
+ window.requestMessages().done(function () {
+ init.call(App, options);
+ });
+ });
+
+ return App;
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/create-view.js b/server/sonar-web/src/main/js/apps/groups/create-view.js
new file mode 100644
index 00000000000..8d5cfce55aa
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/create-view.js
@@ -0,0 +1,30 @@
+define([
+ './group',
+ './form-view'
+], function (Group, FormView) {
+
+ return FormView.extend({
+
+ sendRequest: function () {
+ var that = this,
+ group = new Group({
+ name: this.$('#create-group-name').val(),
+ description: this.$('#create-group-description').val()
+ });
+ this.disableForm();
+ return group.save(null, {
+ statusCode: {
+ // do not show global error
+ 400: null
+ }
+ }).done(function () {
+ that.collection.refresh();
+ that.close();
+ }).fail(function (jqXHR) {
+ that.enableForm();
+ that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings);
+ });
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/delete-view.js b/server/sonar-web/src/main/js/apps/groups/delete-view.js
new file mode 100644
index 00000000000..137aa768da2
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/delete-view.js
@@ -0,0 +1,32 @@
+define([
+ 'components/common/modal-form',
+ './templates'
+], function (ModalForm) {
+
+ return ModalForm.extend({
+ template: Templates['groups-delete'],
+
+ onFormSubmit: function (e) {
+ this._super(e);
+ this.sendRequest();
+ },
+
+ sendRequest: function () {
+ var that = this,
+ collection = this.model.collection;
+ return this.model.destroy({
+ wait: true,
+ statusCode: {
+ // do not show global error
+ 400: null
+ }
+ }).done(function () {
+ collection.total--;
+ that.close();
+ }).fail(function (jqXHR) {
+ that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings);
+ });
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/form-view.js b/server/sonar-web/src/main/js/apps/groups/form-view.js
new file mode 100644
index 00000000000..e79ea6eec65
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/form-view.js
@@ -0,0 +1,25 @@
+define([
+ 'components/common/modal-form',
+ './templates'
+], function (ModalForm) {
+
+ return ModalForm.extend({
+ template: Templates['groups-form'],
+
+ onRender: function () {
+ this._super();
+ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' });
+ },
+
+ onClose: function () {
+ this._super();
+ this.$('[data-toggle="tooltip"]').tooltip('destroy');
+ },
+
+ onFormSubmit: function (e) {
+ this._super(e);
+ this.sendRequest();
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/group.js b/server/sonar-web/src/main/js/apps/groups/group.js
new file mode 100644
index 00000000000..406f9ba3a3a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/group.js
@@ -0,0 +1,35 @@
+define(function () {
+
+ return Backbone.Model.extend({
+ urlRoot: function () {
+ return baseUrl + '/api/usergroups';
+ },
+
+ sync: function (method, model, options) {
+ var opts = options || {};
+ if (method === 'create') {
+ _.defaults(opts, {
+ url: this.urlRoot() + '/create',
+ type: 'POST',
+ data: _.pick(model.toJSON(), 'name', 'description')
+ });
+ }
+ if (method === 'update') {
+ _.defaults(opts, {
+ url: this.urlRoot() + '/update',
+ type: 'POST',
+ data: _.pick(model.toJSON(), 'id', 'name', 'description')
+ });
+ }
+ if (method === 'delete') {
+ _.defaults(opts, {
+ url: this.urlRoot() + '/delete',
+ type: 'POST',
+ data: { id: this.id }
+ });
+ }
+ return Backbone.ajax(opts);
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/groups.js b/server/sonar-web/src/main/js/apps/groups/groups.js
new file mode 100644
index 00000000000..dcfbb8c731b
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/groups.js
@@ -0,0 +1,40 @@
+define([
+ './group'
+], function (Group) {
+
+ return Backbone.Collection.extend({
+ model: Group,
+
+ url: function () {
+ return baseUrl + '/api/usergroups/search';
+ },
+
+ parse: function (r) {
+ this.total = +r.total;
+ this.p = +r.p;
+ this.ps = +r.ps;
+ return r.groups;
+ },
+
+ fetch: function (options) {
+ var d = (options && options.data) || {};
+ this.q = d.q;
+ return this._super(options);
+ },
+
+ fetchMore: function () {
+ var p = this.p + 1;
+ return this.fetch({ add: true, remove: false, data: { p: p, ps: this.ps, q: this.q } });
+ },
+
+ refresh: function () {
+ return this.fetch({ reset: true, data: { q: this.q } });
+ },
+
+ hasMore: function () {
+ return this.total > this.p * this.ps;
+ }
+
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/header-view.js b/server/sonar-web/src/main/js/apps/groups/header-view.js
new file mode 100644
index 00000000000..da6f7f60919
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/header-view.js
@@ -0,0 +1,25 @@
+define([
+ './create-view',
+ './templates'
+], function (CreateView) {
+
+ return Marionette.ItemView.extend({
+ template: Templates['groups-header'],
+
+ events: {
+ 'click #groups-create': 'onCreateClick'
+ },
+
+ onCreateClick: function (e) {
+ e.preventDefault();
+ this.createGroup();
+ },
+
+ createGroup: function () {
+ new CreateView({
+ collection: this.collection
+ }).render();
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/layout.js b/server/sonar-web/src/main/js/apps/groups/layout.js
new file mode 100644
index 00000000000..a60fb06f35f
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/layout.js
@@ -0,0 +1,16 @@
+define([
+ './templates'
+], function () {
+
+ return Marionette.Layout.extend({
+ template: Templates['groups-layout'],
+
+ regions: {
+ headerRegion: '#groups-header',
+ searchRegion: '#groups-search',
+ listRegion: '#groups-list',
+ listFooterRegion: '#groups-list-footer'
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/list-footer-view.js b/server/sonar-web/src/main/js/apps/groups/list-footer-view.js
new file mode 100644
index 00000000000..3c0fbe198c5
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/list-footer-view.js
@@ -0,0 +1,34 @@
+define([
+ './templates'
+], function () {
+
+ return Marionette.ItemView.extend({
+ template: Templates['groups-list-footer'],
+
+ collectionEvents: {
+ 'all': 'render'
+ },
+
+ events: {
+ 'click #groups-fetch-more': 'onMoreClick'
+ },
+
+ onMoreClick: function (e) {
+ e.preventDefault();
+ this.fetchMore();
+ },
+
+ fetchMore: function () {
+ this.collection.fetchMore();
+ },
+
+ serializeData: function () {
+ return _.extend(this._super(), {
+ total: this.collection.total,
+ count: this.collection.length,
+ more: this.collection.hasMore()
+ });
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/list-item-view.js b/server/sonar-web/src/main/js/apps/groups/list-item-view.js
new file mode 100644
index 00000000000..43eaa5b0d24
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/list-item-view.js
@@ -0,0 +1,59 @@
+define([
+ './update-view',
+ './delete-view',
+ './users-view',
+ './templates'
+], function (UpdateView, DeleteView, UsersView) {
+
+ return Marionette.ItemView.extend({
+ tagName: 'li',
+ className: 'panel panel-vertical',
+ template: Templates['groups-list-item'],
+
+ events: {
+ 'click .js-group-update': 'onUpdateClick',
+ 'click .js-group-delete': 'onDeleteClick',
+ 'click .js-group-users': 'onUsersClick'
+ },
+
+ onRender: function () {
+ this.$el.attr('data-id', this.model.id);
+ this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' });
+ },
+
+ onClose: function () {
+ this.$('[data-toggle="tooltip"]').tooltip('destroy');
+ },
+
+ onUpdateClick: function (e) {
+ e.preventDefault();
+ this.updateGroup();
+ },
+
+ onDeleteClick: function (e) {
+ e.preventDefault();
+ this.deleteGroup();
+ },
+
+ onUsersClick: function (e) {
+ e.preventDefault();
+ this.showUsers();
+ },
+
+ updateGroup: function () {
+ new UpdateView({
+ model: this.model,
+ collection: this.model.collection
+ }).render();
+ },
+
+ deleteGroup: function () {
+ new DeleteView({ model: this.model }).render();
+ },
+
+ showUsers: function () {
+ new UsersView({ model: this.model }).render();
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/list-view.js b/server/sonar-web/src/main/js/apps/groups/list-view.js
new file mode 100644
index 00000000000..138c36b7619
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/list-view.js
@@ -0,0 +1,11 @@
+define([
+ './list-item-view',
+ './templates'
+], function (ListItemView) {
+
+ return Marionette.CollectionView.extend({
+ tagName: 'ul',
+ itemView: ListItemView
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/search-view.js b/server/sonar-web/src/main/js/apps/groups/search-view.js
new file mode 100644
index 00000000000..1540d7eb36e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/search-view.js
@@ -0,0 +1,49 @@
+define([
+ './templates'
+], function () {
+
+ return Marionette.ItemView.extend({
+ template: Templates['groups-search'],
+
+ events: {
+ 'submit #groups-search-form': 'onFormSubmit',
+ 'search #groups-search-query': 'debouncedOnKeyUp',
+ 'keyup #groups-search-query': 'debouncedOnKeyUp'
+ },
+
+ initialize: function () {
+ this._bufferedValue = null;
+ this.debouncedOnKeyUp = _.debounce(this.onKeyUp, 400);
+ },
+
+ onRender: function () {
+ this.delegateEvents();
+ },
+
+ onFormSubmit: function (e) {
+ e.preventDefault();
+ this.debouncedOnKeyUp();
+ },
+
+ onKeyUp: function () {
+ var q = this.getQuery();
+ if (q === this._bufferedValue) {
+ return;
+ }
+ this._bufferedValue = this.getQuery();
+ if (this.searchRequest != null) {
+ this.searchRequest.abort();
+ }
+ this.searchRequest = this.search(q);
+ },
+
+ getQuery: function () {
+ return this.$('#groups-search-query').val();
+ },
+
+ search: function (q) {
+ return this.collection.fetch({ reset: true, data: { q: q } });
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-delete.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-delete.hbs
new file mode 100644
index 00000000000..0644817633e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-delete.hbs
@@ -0,0 +1,13 @@
+<form id="delete-group-form" autocomplete="off">
+ <div class="modal-head">
+ <h2>Delete Group</h2>
+ </div>
+ <div class="modal-body">
+ <div class="js-modal-messages"></div>
+ Are you sure you want to delete "{{name}}"?
+ </div>
+ <div class="modal-foot">
+ <button id="delete-group-submit">Delete</button>
+ <a href="#" class="js-modal-close" id="delete-group-cancel">Cancel</a>
+ </div>
+</form>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-form.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-form.hbs
new file mode 100644
index 00000000000..a0927b33a73
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-form.hbs
@@ -0,0 +1,24 @@
+<form id="create-group-form" autocomplete="off">
+ <div class="modal-head">
+ <h2>{{#if id}}Update{{else}}Create{{/if}} Group</h2>
+ </div>
+ <div class="modal-body">
+ <div class="js-modal-messages"></div>
+ <div class="modal-field">
+ <label for="create-group-name">Name<em class="mandatory">*</em></label>
+ {{! keep this fake field to hack browser autofill }}
+ <input id="create-group-name-fake" name="name-fake" type="text" class="hidden">
+ <input id="create-group-name" name="name" type="text" size="50" maxlength="255" required value="{{name}}">
+ </div>
+ <div class="modal-field">
+ <label for="create-group-description">Description</label>
+ {{! keep this fake field to hack browser autofill }}
+ <textarea id="create-group-description-fake" name="description-fake" class="hidden"></textarea>
+ <textarea id="create-group-description" name="description">{{description}}</textarea>
+ </div>
+ </div>
+ <div class="modal-foot">
+ <button id="create-group-submit">{{#if id}}Update{{else}}Create{{/if}}</button>
+ <a href="#" class="js-modal-close" id="create-group-cancel">Cancel</a>
+ </div>
+</form>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-header.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-header.hbs
new file mode 100644
index 00000000000..19ba74febf8
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-header.hbs
@@ -0,0 +1,9 @@
+<header class="page-header">
+ <h1 class="page-title">{{t 'user_groups.page'}}</h1>
+ <div class="page-actions">
+ <div class="button-group">
+ <button id="groups-create">Create Group</button>
+ </div>
+ </div>
+ <p class="page-description">{{t 'user_groups.page.description'}}</p>
+</header>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-layout.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-layout.hbs
new file mode 100644
index 00000000000..4cad08c767e
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-layout.hbs
@@ -0,0 +1,6 @@
+<div class="page">
+ <div id="groups-header"></div>
+ <div id="groups-search"></div>
+ <div id="groups-list"></div>
+ <div id="groups-list-footer"></div>
+</div>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-list-footer.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-list-footer.hbs
new file mode 100644
index 00000000000..841ab40ecd9
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-list-footer.hbs
@@ -0,0 +1,6 @@
+<footer class="spacer-top note text-center">
+ {{count}}/{{total}} shown
+ {{#if more}}
+ <a id="groups-fetch-more" class="spacer-left" href="#">show more</a>
+ {{/if}}
+</footer>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-list-item.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-list-item.hbs
new file mode 100644
index 00000000000..611cc382493
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-list-item.hbs
@@ -0,0 +1,16 @@
+<div class="pull-right big-spacer-left nowrap">
+ <a class="js-group-update icon-edit little-spacer-right" title="Update Details" data-toggle="tooltip" href="#"></a>
+ <a class="js-group-delete icon-delete" title="Deactivate" data-toggle="tooltip" href="#"></a>
+</div>
+
+<div class="display-inline-block text-top width-20">
+ <strong class="js-group-name">{{name}}</strong>
+</div>
+
+<div class="display-inline-block text-top big-spacer-left width-10">
+ Members: <a class="js-group-users" href="#">{{membersCount}}</a>
+</div>
+
+<div class="display-inline-block text-top big-spacer-left width-50">
+ <span class="js-group-description">{{description}}</span>
+</div>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs
new file mode 100644
index 00000000000..5e81ec0b32a
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-search.hbs
@@ -0,0 +1,6 @@
+<div class="panel panel-vertical bordered-bottom spacer-bottom">
+ <form id="groups-search-form" class="search-box">
+ <button id="groups-search-submit" class="search-box-submit button-clean"><i class="icon-search"></i></button>
+ <input id="groups-search-query" class="search-box-input" type="search" name="q" placeholder="Search" maxlength="100">
+ </form>
+</div>
diff --git a/server/sonar-web/src/main/js/apps/groups/templates/groups-users.hbs b/server/sonar-web/src/main/js/apps/groups/templates/groups-users.hbs
new file mode 100644
index 00000000000..eb346c0e31b
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/templates/groups-users.hbs
@@ -0,0 +1,10 @@
+<div class="modal-head">
+ <h2>Update users</h2>
+</div>
+<div class="modal-body">
+ <div class="js-modal-messages"></div>
+ <div id="groups-users"></div>
+</div>
+<div class="modal-foot">
+ <a href="#" class="js-modal-close" id="groups-users-done">Done</a>
+</div>
diff --git a/server/sonar-web/src/main/js/apps/groups/update-view.js b/server/sonar-web/src/main/js/apps/groups/update-view.js
new file mode 100644
index 00000000000..71383a1793d
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/update-view.js
@@ -0,0 +1,29 @@
+define([
+ './form-view'
+], function (FormView) {
+
+ return FormView.extend({
+
+ sendRequest: function () {
+ var that = this;
+ this.model.set({
+ name: this.$('#create-group-name').val(),
+ description: this.$('#create-group-description').val()
+ });
+ this.disableForm();
+ return this.model.save(null, {
+ statusCode: {
+ // do not show global error
+ 400: null
+ }
+ }).done(function () {
+ that.collection.refresh();
+ that.close();
+ }).fail(function (jqXHR) {
+ that.enableForm();
+ that.showErrors(jqXHR.responseJSON.errors, jqXHR.responseJSON.warnings);
+ });
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/groups/users-view.js b/server/sonar-web/src/main/js/apps/groups/users-view.js
new file mode 100644
index 00000000000..7786d63fe44
--- /dev/null
+++ b/server/sonar-web/src/main/js/apps/groups/users-view.js
@@ -0,0 +1,42 @@
+define([
+ 'components/common/modals',
+ 'components/common/select-list',
+ './templates'
+], function (Modal) {
+
+ return Modal.extend({
+ template: Templates['groups-users'],
+
+ onRender: function () {
+ this._super();
+ new window.SelectList({
+ el: this.$('#groups-users'),
+ width: '100%',
+ readOnly: false,
+ focusSearch: false,
+ format: function (item) {
+ return item.name + '<br><span class="note">' + item.login + '</span>';
+ },
+ queryParam: 'q',
+ searchUrl: baseUrl + '/api/usergroups/users?ps=100&id=' + this.model.id,
+ selectUrl: baseUrl + '/api/usergroups/add_user',
+ deselectUrl: baseUrl + '/api/usergroups/remove_user',
+ extra: {
+ groupId: this.model.id
+ },
+ selectParameter: 'userLogin',
+ selectParameterValue: 'login',
+ parse: function (r) {
+ this.more = false;
+ return r.users;
+ }
+ });
+ },
+
+ onClose: function () {
+ this.model.collection.refresh();
+ this._super();
+ }
+ });
+
+});
diff --git a/server/sonar-web/src/main/js/apps/issues/templates/issues-issue-filter.hbs b/server/sonar-web/src/main/js/apps/issues/templates/issues-issue-filter.hbs
index 875bc3bc4a5..f7f1bd1b215 100644
--- a/server/sonar-web/src/main/js/apps/issues/templates/issues-issue-filter.hbs
+++ b/server/sonar-web/src/main/js/apps/issues/templates/issues-issue-filter.hbs
@@ -1,5 +1,5 @@
-<div class="issue-meta">
- <a class="issue-action issue-action-with-options js-issue-filter" href="#">
+<li class="issue-meta">
+ <button class="button-link issue-action issue-action-with-options js-issue-filter">
<i class="icon-filter icon-half-transparent"></i>&nbsp;<i class="icon-dropdown"></i>
- </a>
-</div>
+ </button>
+</li>
diff --git a/server/sonar-web/src/main/js/apps/provisioning/delete-view.js b/server/sonar-web/src/main/js/apps/provisioning/delete-view.js
index 2ff38de169f..7797227aa40 100644
--- a/server/sonar-web/src/main/js/apps/provisioning/delete-view.js
+++ b/server/sonar-web/src/main/js/apps/provisioning/delete-view.js
@@ -6,8 +6,8 @@ define([
return ModalForm.extend({
template: Templates['provisioning-delete'],
- onFormSubmit: function () {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
+ onFormSubmit: function (e) {
+ this._super(e);
this.sendRequest();
},
diff --git a/server/sonar-web/src/main/js/apps/provisioning/form-view.js b/server/sonar-web/src/main/js/apps/provisioning/form-view.js
index ed7fe702f2c..ce359c6fa07 100644
--- a/server/sonar-web/src/main/js/apps/provisioning/form-view.js
+++ b/server/sonar-web/src/main/js/apps/provisioning/form-view.js
@@ -7,17 +7,17 @@ define([
template: Templates['provisioning-form'],
onRender: function () {
- ModalForm.prototype.onRender.apply(this, arguments);
+ this._super();
this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' });
},
onClose: function () {
- ModalForm.prototype.onClose.apply(this, arguments);
+ this._super();
this.$('[data-toggle="tooltip"]').tooltip('destroy');
},
- onFormSubmit: function () {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
+ onFormSubmit: function (e) {
+ this._super(e);
this.sendRequest();
}
diff --git a/server/sonar-web/src/main/js/apps/provisioning/list-footer-view.js b/server/sonar-web/src/main/js/apps/provisioning/list-footer-view.js
index 6dc243e7b67..902b9322372 100644
--- a/server/sonar-web/src/main/js/apps/provisioning/list-footer-view.js
+++ b/server/sonar-web/src/main/js/apps/provisioning/list-footer-view.js
@@ -23,7 +23,7 @@ define([
},
serializeData: function () {
- return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+ return _.extend(this._super(), {
total: this.collection.total,
count: this.collection.length,
more: this.collection.hasMore()
diff --git a/server/sonar-web/src/main/js/apps/provisioning/projects.js b/server/sonar-web/src/main/js/apps/provisioning/projects.js
index 44f1c5b4b5a..a5c26347c59 100644
--- a/server/sonar-web/src/main/js/apps/provisioning/projects.js
+++ b/server/sonar-web/src/main/js/apps/provisioning/projects.js
@@ -19,7 +19,7 @@ define([
fetch: function (options) {
var d = (options && options.data) || {};
this.q = d.q;
- return Backbone.Collection.prototype.fetch.apply(this, arguments);
+ return this._super(options);
},
fetchMore: function () {
diff --git a/server/sonar-web/src/main/js/apps/users/change-password-view.js b/server/sonar-web/src/main/js/apps/users/change-password-view.js
index cd2a892fc2b..6187333c9e6 100644
--- a/server/sonar-web/src/main/js/apps/users/change-password-view.js
+++ b/server/sonar-web/src/main/js/apps/users/change-password-view.js
@@ -6,8 +6,8 @@ define([
return ModalForm.extend({
template: Templates['users-change-password'],
- onFormSubmit: function () {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
+ onFormSubmit: function (e) {
+ this._super(e);
this.sendRequest();
},
diff --git a/server/sonar-web/src/main/js/apps/users/deactivate-view.js b/server/sonar-web/src/main/js/apps/users/deactivate-view.js
index cf4c4654984..37c71d4a94b 100644
--- a/server/sonar-web/src/main/js/apps/users/deactivate-view.js
+++ b/server/sonar-web/src/main/js/apps/users/deactivate-view.js
@@ -6,8 +6,8 @@ define([
return ModalForm.extend({
template: Templates['users-deactivate'],
- onFormSubmit: function () {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
+ onFormSubmit: function (e) {
+ this._super(e);
this.sendRequest();
},
diff --git a/server/sonar-web/src/main/js/apps/users/form-view.js b/server/sonar-web/src/main/js/apps/users/form-view.js
index 2cf2e1ac3f1..f1c7f602d14 100644
--- a/server/sonar-web/src/main/js/apps/users/form-view.js
+++ b/server/sonar-web/src/main/js/apps/users/form-view.js
@@ -9,23 +9,23 @@ define([
template: Templates['users-form'],
events: function () {
- return _.extend(ModalForm.prototype.events.apply(this, arguments), {
+ return _.extend(this._super(), {
'click #create-user-add-scm-account': 'onAddScmAccountClick'
});
},
onRender: function () {
- ModalForm.prototype.onRender.apply(this, arguments);
+ this._super();
this.$('[data-toggle="tooltip"]').tooltip({ container: 'body', placement: 'bottom' });
},
onClose: function () {
- ModalForm.prototype.onClose.apply(this, arguments);
+ this._super();
this.$('[data-toggle="tooltip"]').tooltip('destroy');
},
- onFormSubmit: function () {
- ModalForm.prototype.onFormSubmit.apply(this, arguments);
+ onFormSubmit: function (e) {
+ this._super(e);
this.sendRequest();
},
diff --git a/server/sonar-web/src/main/js/apps/users/groups-view.js b/server/sonar-web/src/main/js/apps/users/groups-view.js
index b242f435773..6a874070b66 100644
--- a/server/sonar-web/src/main/js/apps/users/groups-view.js
+++ b/server/sonar-web/src/main/js/apps/users/groups-view.js
@@ -9,28 +9,34 @@ define([
itemTemplate: Templates['users-group'],
onRender: function () {
- Modal.prototype.onRender.apply(this, arguments);
+ this._super();
new window.SelectList({
el: this.$('#users-groups'),
width: '100%',
- readOnly: true,
+ readOnly: false,
focusSearch: false,
format: function (item) {
return item.name + '<br><span class="note">' + item.description + '</span>';
},
+ queryParam: 'q',
searchUrl: baseUrl + '/api/users/groups?ps=100&login=' + this.model.id,
- selectUrl: baseUrl + '/api/qualityprofiles/add_project',
- deselectUrl: baseUrl + '/api/qualityprofiles/remove_project',
+ selectUrl: baseUrl + '/api/usergroups/add_user',
+ deselectUrl: baseUrl + '/api/usergroups/remove_user',
extra: {
- profileKey: key
+ userLogin: this.model.id
},
- selectParameter: 'projectUuid',
- selectParameterValue: 'uuid',
+ selectParameter: 'groupId',
+ selectParameterValue: 'id',
parse: function (r) {
this.more = false;
return r.groups;
}
});
+ },
+
+ onClose: function () {
+ this.model.collection.refresh();
+ Modal.prototype.onClose.apply(this, arguments);
}
});
diff --git a/server/sonar-web/src/main/js/apps/users/list-footer-view.js b/server/sonar-web/src/main/js/apps/users/list-footer-view.js
index 968ad0990d5..cf802586354 100644
--- a/server/sonar-web/src/main/js/apps/users/list-footer-view.js
+++ b/server/sonar-web/src/main/js/apps/users/list-footer-view.js
@@ -23,7 +23,7 @@ define([
},
serializeData: function () {
- return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+ return _.extend(this._super(), {
total: this.collection.total,
count: this.collection.length,
more: this.collection.hasMore()
diff --git a/server/sonar-web/src/main/js/apps/users/list-item-view.js b/server/sonar-web/src/main/js/apps/users/list-item-view.js
index c6a81a2e71f..99aa973579b 100644
--- a/server/sonar-web/src/main/js/apps/users/list-item-view.js
+++ b/server/sonar-web/src/main/js/apps/users/list-item-view.js
@@ -101,7 +101,7 @@ define([
scmAccountsLimit = scmAccounts.length > this.scmLimit ? this.scmLimit - 1 : this.scmLimit,
groups = this.model.get('groups'),
groupsLimit = groups.length > this.groupsLimit ? this.groupsLimit - 1 : this.groupsLimit;
- return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
+ return _.extend(this._super(), {
firstScmAccounts: _.first(scmAccounts, scmAccountsLimit),
moreScmAccountsCount: scmAccounts.length - scmAccountsLimit,
firstGroups: _.first(groups, groupsLimit),
diff --git a/server/sonar-web/src/main/js/apps/users/users.js b/server/sonar-web/src/main/js/apps/users/users.js
index adf80b669da..9c45979a9fe 100644
--- a/server/sonar-web/src/main/js/apps/users/users.js
+++ b/server/sonar-web/src/main/js/apps/users/users.js
@@ -19,7 +19,7 @@ define([
fetch: function (options) {
var d = (options && options.data) || {};
this.q = d.q;
- return Backbone.Collection.prototype.fetch.apply(this, arguments);
+ return this._super(options);
},
fetchMore: function () {
diff --git a/server/sonar-web/src/main/js/components/common/select-list.js b/server/sonar-web/src/main/js/components/common/select-list.js
index 480fbd9d690..5716ed2fa10 100644
--- a/server/sonar-web/src/main/js/components/common/select-list.js
+++ b/server/sonar-web/src/main/js/components/common/select-list.js
@@ -329,7 +329,8 @@ define(function () {
search: function () {
var query = this.$('.select-list-search-control input').val(),
hasQuery = query.length > 0,
- that = this;
+ that = this,
+ data = {};
this.$('.select-list-check-control').toggleClass('disabled', hasQuery);
this.$('.select-list-search-control').toggleClass('disabled', !hasQuery);
@@ -338,10 +339,11 @@ define(function () {
this.showFetchSpinner();
this.currentFilter = 'all';
+ data[this.settings.queryParam] = query;
this.collection.fetch({
url: this.settings.searchUrl,
reset: true,
- data: { query: query },
+ data: data,
success: function () {
that.hideFetchSpinner();
},
@@ -431,6 +433,8 @@ define(function () {
return r.results;
},
+ queryParam: 'query',
+
labels: {
selected: 'Selected',
deselected: 'Deselected',
diff --git a/server/sonar-web/src/main/js/components/issue/issue-view.js b/server/sonar-web/src/main/js/components/issue/issue-view.js
index 98d095d221d..1b166bb87df 100644
--- a/server/sonar-web/src/main/js/components/issue/issue-view.js
+++ b/server/sonar-web/src/main/js/components/issue/issue-view.js
@@ -56,6 +56,14 @@ define([
this.$el.attr('data-key', this.model.get('key'));
},
+ disableControls: function () {
+ this.$(':input').prop('disabled', true);
+ },
+
+ enableControls: function () {
+ this.$(':input').prop('disabled', false);
+ },
+
resetIssue: function (options) {
var that = this;
var key = this.model.get('key'),
@@ -132,6 +140,7 @@ define([
var commentKey = $(e.target).closest('[data-comment-key]').data('comment-key'),
confirmMsg = $(e.target).data('confirm-msg');
if (confirm(confirmMsg)) {
+ this.disableControls();
return $.ajax({
type: 'POST',
url: baseUrl + '/api/issues/delete_comment?key=' + commentKey
@@ -218,6 +227,7 @@ define([
action: function (action) {
var that = this;
+ this.disableControls();
return $.post(baseUrl + '/api/issues/do_action', {
issue: this.model.id,
actionKey: action
diff --git a/server/sonar-web/src/main/js/components/issue/manual-issue-view.js b/server/sonar-web/src/main/js/components/issue/manual-issue-view.js
index c1f60b486e6..1b043544a44 100644
--- a/server/sonar-web/src/main/js/components/issue/manual-issue-view.js
+++ b/server/sonar-web/src/main/js/components/issue/manual-issue-view.js
@@ -1,10 +1,9 @@
define([
+ './models/issue',
'./templates'
-], function () {
+], function (Issue) {
- var $ = jQuery,
- API_ISSUE = baseUrl + '/api/issues/show',
- API_ADD_MANUAL_ISSUE = baseUrl + '/api/issues/create';
+ var $ = jQuery;
return Marionette.ItemView.extend({
template: Templates['manual-issue'],
@@ -44,68 +43,35 @@ define([
}
},
- showSpinner: function () {
- this.$('.js-submit').hide();
- this.$('.js-spinner').show();
- },
-
- hideSpinner: function () {
- this.$('.js-submit').show();
- this.$('.js-spinner').hide();
- },
-
- validateFields: function () {
- var message = this.$('[name=message]');
- if (!message.val()) {
- message.addClass('invalid').focus();
- return false;
- }
- return true;
- },
-
formSubmit: function (e) {
var that = this;
e.preventDefault();
- if (!this.validateFields()) {
- return;
- }
- this.showSpinner();
- var data = $(e.currentTarget).serialize();
- $.post(API_ADD_MANUAL_ISSUE, data)
- .done(function (r) {
- if (typeof r === 'string') {
- r = JSON.parse(r);
- }
- that.addIssue(r.issue.key);
- }).fail(function (r) {
- that.hideSpinner();
- if (r.responseJSON && r.responseJSON.errors) {
- that.showError(_.pluck(r.responseJSON.errors, 'msg').join('. '));
- }
- });
+ var issue = new Issue({
+ component: this.options.component,
+ line: this.options.line,
+ message: this.$('[name="message"]').val(),
+ rule: this.$('[name="rule"]').val()
+ });
+ issue.save().done(function () {
+ that.addIssue(issue);
+ });
},
- addIssue: function (key) {
+ addIssue: function (issue) {
var that = this;
- return $.get(API_ISSUE, { key: key }).done(function (r) {
- that.trigger('add', r.issue);
+ return issue.fetch().done(function () {
+ that.trigger('add', issue);
that.close();
});
},
- showError: function (msg) {
- this.$('.code-issue-errors').removeClass('hidden').text(msg);
- },
-
cancel: function (e) {
e.preventDefault();
this.close();
},
serializeData: function () {
- return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), {
- line: this.options.line,
- component: this.options.component,
+ return _.extend(this._super(), {
rules: _.sortBy(this.rules, 'name')
});
}
diff --git a/server/sonar-web/src/main/js/components/issue/models/issue.js b/server/sonar-web/src/main/js/components/issue/models/issue.js
index 1c5e928818e..af5dd980c27 100644
--- a/server/sonar-web/src/main/js/components/issue/models/issue.js
+++ b/server/sonar-web/src/main/js/components/issue/models/issue.js
@@ -1,4 +1,4 @@
-define([], function () {
+define(function () {
return Backbone.Model.extend({
idAttribute: 'key',
@@ -7,8 +7,40 @@ define([], function () {
return baseUrl + '/api/issues/show?key=' + this.get('key');
},
+ urlRoot: function () {
+ return baseUrl + '/api/issues';
+ },
+
parse: function (r) {
return r.issue ? r.issue : r;
+ },
+
+ sync: function (method, model, options) {
+ var opts = options || {};
+ opts.contentType = 'application/x-www-form-urlencoded';
+ if (method === 'read') {
+ _.extend(opts, {
+ type: 'GET',
+ url: this.urlRoot() + '/show',
+ data: { key: model.id }
+ });
+ }
+ if (method === 'create') {
+ _.extend(opts, {
+ type: 'POST',
+ url: this.urlRoot() + '/create',
+ data: {
+ component: model.get('component'),
+ line: model.get('line'),
+ message: model.get('message'),
+ rule: model.get('rule'),
+ severity: model.get('severity')
+ }
+ });
+ }
+ var xhr = options.xhr = Backbone.ajax(opts);
+ model.trigger('request', model, xhr, options);
+ return xhr;
}
});
diff --git a/server/sonar-web/src/main/js/components/issue/templates/issue.hbs b/server/sonar-web/src/main/js/components/issue/templates/issue.hbs
index f5a2d5e2fda..ba8e21bcc44 100644
--- a/server/sonar-web/src/main/js/components/issue/templates/issue.hbs
+++ b/server/sonar-web/src/main/js/components/issue/templates/issue.hbs
@@ -3,27 +3,29 @@
<table class="issue-table">
<tr>
<td>
- <div class="issue-message">{{message}} <a class="js-issue-rule issue-rule icon-ellipsis-h"></a></div>
+ <div class="issue-message">
+ {{message}}&nbsp;<button class="button-link js-issue-rule issue-rule icon-ellipsis-h"></button>
+ </div>
</td>
<td class="issue-table-meta-cell issue-table-meta-cell-first">
- <div class="issue-meta-list">
- <div class="issue-meta">
- <a class="issue-action issue-action-with-options js-issue-show-changelog" title="{{dt creationDate}}">
+ <ul class="list-inline issue-meta-list">
+ <li class="issue-meta">
+ <button class="button-link issue-action issue-action-with-options js-issue-show-changelog" title="{{dt creationDate}}">
<span class="issue-meta-label">{{fromNow creationDate}}</span>&nbsp;<i class="icon-dropdown"></i>
- </a>
- </div>
+ </button>
+ </li>
{{#if line}}
- <div class="issue-meta">
+ <li class="issue-meta">
<span class="issue-meta-label" title="{{t 'line_number'}}">L{{line}}</span>
- </div>
+ </li>
{{/if}}
- <div class="issue-meta">
- <a class="issue-action js-issue-permalink icon-link" href="{{permalink}}" target="_blank"></a>
- </div>
- </div>
+ <li class="issue-meta">
+ <a class="js-issue-permalink icon-link" href="{{permalink}}" target="_blank"></a>
+ </li>
+ </ul>
</td>
</tr>
</table>
@@ -31,38 +33,38 @@
<table class="issue-table">
<tr>
<td>
- <div class="issue-meta-list">
- <div class="issue-meta">
+ <ul class="list-inline issue-meta-list">
+ <li class="issue-meta">
{{#inArray actions "set_severity"}}
- <a class="issue-action issue-action-with-options js-issue-set-severity">
+ <button class="button-link issue-action issue-action-with-options js-issue-set-severity">
<span class="issue-meta-label">{{severityHelper severity}}</span>&nbsp;<i class="icon-dropdown"></i>
- </a>
+ </button>
{{else}}
{{severityHelper severity}}
{{/inArray}}
- </div>
+ </li>
- <div class="issue-meta">
+ <li class="issue-meta">
{{#notEmpty transitions}}
- <a class="issue-action issue-action-with-options js-issue-transition">
+ <button class="button-link issue-action issue-action-with-options js-issue-transition">
<span class="issue-meta-label">{{statusHelper status resolution}}</span>&nbsp;<i
class="icon-dropdown"></i>
- </a>
+ </button>
{{else}}
{{statusHelper status resolution}}
{{/notEmpty}}
- </div>
+ </li>
- <div class="issue-meta">
+ <li class="issue-meta">
{{#inArray actions "assign"}}
- <a class="issue-action issue-action-with-options js-issue-assign">
+ <button class="button-link issue-action issue-action-with-options js-issue-assign">
{{#if assignee}}
{{#ifShowAvatars}}
<span class="text-top">{{avatarHelper assigneeEmail 16}}</span>
{{/ifShowAvatars}}
{{/if}}
<span class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span>&nbsp;<i class="icon-dropdown"></i>
- </a>
+ </button>
{{else}}
{{#if assignee}}
{{#ifShowAvatars}}
@@ -71,64 +73,66 @@
{{/if}}
<span class="issue-meta-label">{{#if assignee}}{{default assigneeName assignee}}{{else}}{{t 'unassigned'}}{{/if}}</span>
{{/inArray}}
- </div>
-
- {{#inArray actions "assign_to_me"}}
- <a class="js-issue-assign-to-me"></a>
- {{/inArray}}
+ </li>
- <div class="issue-meta">
+ <li class="issue-meta">
{{#inArray actions "plan"}}
- <a class="issue-action issue-action-with-options js-issue-plan">
+ <button class="button-link issue-action issue-action-with-options js-issue-plan">
<span
class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span>&nbsp;<i
class="icon-dropdown"></i>
- </a>
+ </button>
{{else}}
<span
class="issue-meta-label">{{#if actionPlan}}{{default actionPlanName actionPlan}}{{else}}{{t 'issue.unplanned'}}{{/if}}</span>
{{/inArray}}
- </div>
+ </li>
{{#if debt}}
- <div class="issue-meta">
+ <li class="issue-meta">
<span class="issue-meta-label">
{{tp 'issue.x_debt' debt}}
</span>
- </div>
+ </li>
{{/if}}
{{#inArray actions "comment"}}
- <div class="issue-meta">
- <a class="issue-action js-issue-comment"><span
- class="issue-meta-label">{{t 'issue.comment.formlink' }}</span></a>
- </div>
+ <li class="issue-meta">
+ <button class="button-link issue-action js-issue-comment"><span
+ class="issue-meta-label">{{t 'issue.comment.formlink' }}</span></button>
+ </li>
{{/inArray}}
{{#ifHasExtraActions actions}}
- <div class="issue-meta">
- <a class="issue-action issue-action-with-options js-issue-more">
+ <li class="issue-meta">
+ <button class="button-link issue-action issue-action-with-options js-issue-more">
<span class="issue-meta-label">{{t 'more'}}</span>&nbsp;<i class="icon-dropdown"></i>
- </a>
- </div>
+ </button>
+ </li>
{{/ifHasExtraActions}}
- </div>
+ </ul>
+
+ {{#inArray actions "assign_to_me"}}
+ <button class="button-link hidden js-issue-assign-to-me"></button>
+ {{/inArray}}
</td>
<td class="issue-table-meta-cell">
- <div class="issue-meta js-issue-tags">
- {{#inArray actions "set_tags"}}
- <a class="issue-action issue-action-with-options js-issue-edit-tags">
+ <ul class="list-inline">
+ <li class="issue-meta js-issue-tags">
+ {{#inArray actions "set_tags"}}
+ <button class="button-link issue-action issue-action-with-options js-issue-edit-tags">
<span>
<i class="icon-tags icon-half-transparent"></i>&nbsp;<span>{{#if tags}}{{join tags ', '}}{{else}}{{t 'issue.no_tag'}}{{/if}}</span>
</span>&nbsp;<i class="icon-dropdown"></i>
- </a>
- {{else}}
- <span>
+ </button>
+ {{else}}
+ <span>
<i class="icon-tags icon-half-transparent"></i>&nbsp;<span>{{#if tags}}{{join tags ', '}}{{else}}{{t 'issue.no_tag'}}{{/if}}</span>
</span>
- {{/inArray}}
- </div>
+ {{/inArray}}
+ </li>
+ </ul>
</td>
</tr>
</table>
@@ -138,15 +142,16 @@
{{#each comments}}
<div class="issue-comment" data-comment-key="{{key}}">
<div class="issue-comment-author" title="{{userName}}">
- {{#ifShowAvatars}}{{avatarHelper email 16}}{{else}}<i class="icon-comment icon-half-transparent"></i>{{/ifShowAvatars}}&nbsp;{{userName}}
+ {{#ifShowAvatars}}{{avatarHelper email 16}}{{else}}
+ <i class="icon-comment icon-half-transparent"></i>{{/ifShowAvatars}}&nbsp;{{userName}}
</div>
<div class="issue-comment-text markdown">{{{show html htmlText}}}</div>
<div class="issue-comment-age">({{fromNow createdAt}})</div>
<div class="issue-comment-actions">
{{#if updatable}}
- <a class="js-issue-comment-edit icon-edit icon-half-transparent"></a>
- <a class="js-issue-comment-delete icon-delete icon-half-transparent"
- data-confirm-msg="{{t 'issue.comment.delete_confirm_message'}}"></a>
+ <button class="js-issue-comment-edit button-link icon-edit icon-half-transparent"></button>
+ <button class="js-issue-comment-delete button-link icon-delete icon-half-transparent"
+ data-confirm-msg="{{t 'issue.comment.delete_confirm_message'}}"></button>
{{/if}}
</div>
</div>
diff --git a/server/sonar-web/src/main/js/components/issue/templates/manual-issue.hbs b/server/sonar-web/src/main/js/components/issue/templates/manual-issue.hbs
index bbcf333395b..0a38fa2136f 100644
--- a/server/sonar-web/src/main/js/components/issue/templates/manual-issue.hbs
+++ b/server/sonar-web/src/main/js/components/issue/templates/manual-issue.hbs
@@ -1,19 +1,6 @@
-<form action="" class="js-manual-issue-form code-issue-create-form">
- {{! no manual rules }}
- {{! <div class="warning" style="margin: 10px"> }}
- {{! <% if is_admin %> }}
- {{! <%= message('issue.manual.no_rules.admin') -%> }}
- {{! &nbsp;<a href="<%= ApplicationController.root_context -%>/manual_rules/index"><%= message('manage') -%></a> }}
- {{! <% else %> }}
- {{! <%= message('issue.manual.no_rules.non_admin') -%> }}
- {{! <% end %> }}
- {{! &nbsp;<%= link_to_function message('cancel'), 'closeCreateIssueForm(this)' -%> }}
- {{! </div> }}
+<form class="js-manual-issue-form spacer-top spacer-bottom">
- <input type="hidden" name="line" value="{{line}}">
- <input type="hidden" name="component" value="{{component}}">
-
- <div class="code-issue-name">
+ <div class="spacer-bottom">
<select name="rule">
{{#each rules}}
<option value="{{key}}">{{name}}</option>
@@ -21,24 +8,13 @@
</select>
</div>
- <div class="code-issue-msg">
- <table class="width100">
- <tr>
- <td>
- <textarea rows="4" name="message" class="width100 marginbottom5"></textarea>
- </td>
- </tr>
- <tr>
- <td class="js-submit">
- <input type="submit" value="{{t 'create'}}">
- <a class="js-cancel" href="#">{{t 'cancel'}}</a>
- </td>
- <td class="js-spinner" style="display: none;">
- <i class="spinner"></i>
- </td>
- </tr>
- </table>
- <div class="code-issue-errors alert alert-danger hidden"></div>
+ <div class="spacer-top">
+ <textarea rows="4" name="message" class="width-100" required></textarea>
+ </div>
+
+ <div class="spacer-top">
+ <input type="submit" value="{{t 'create'}}">
+ <a class="js-cancel" href="#">{{t 'cancel'}}</a>
</div>
</form>
diff --git a/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js b/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js
index 4816ff2eada..10e9c713e09 100644
--- a/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js
+++ b/server/sonar-web/src/main/js/components/issue/views/comment-form-view.js
@@ -49,6 +49,14 @@ define([
this.options.detailView.updateAfterAction(false);
},
+ disableForm: function () {
+ this.$(':input').prop('disabled', true);
+ },
+
+ enableForm: function () {
+ this.$(':input').prop('disabled', false);
+ },
+
submit: function () {
var that = this;
var text = this.ui.textarea.val(),
@@ -61,9 +69,15 @@ define([
} else {
data.issue = this.options.issue.id;
}
- return $.post(url, data).done(function () {
- that.options.detailView.updateAfterAction(true);
- });
+ this.disableForm();
+ this.options.detailView.disableControls();
+ return $.post(url, data)
+ .done(function () {
+ that.options.detailView.updateAfterAction(true);
+ }).fail(function () {
+ that.enableForm();
+ that.options.detailView.enableControls();
+ });
}
});
diff --git a/server/sonar-web/src/main/js/components/issue/views/transitions-form-view.js b/server/sonar-web/src/main/js/components/issue/views/transitions-form-view.js
index 6558537e225..9d56b101591 100644
--- a/server/sonar-web/src/main/js/components/issue/views/transitions-form-view.js
+++ b/server/sonar-web/src/main/js/components/issue/views/transitions-form-view.js
@@ -20,6 +20,7 @@ define([
submit: function (transition) {
var that = this;
+ this.options.view.disableControls();
return $.ajax({
type: 'POST',
url: baseUrl + '/api/issues/do_transition',
diff --git a/server/sonar-web/src/main/js/components/source-viewer/main.js b/server/sonar-web/src/main/js/components/source-viewer/main.js
index 07dfc55580d..a007145f354 100644
--- a/server/sonar-web/src/main/js/components/source-viewer/main.js
+++ b/server/sonar-web/src/main/js/components/source-viewer/main.js
@@ -479,8 +479,8 @@ define([
line: line,
row: $(e.currentTarget).closest('.source-line')
});
- popup.on('onManualIssueAdded', function (data) {
- that.addIssue(new Issue(data));
+ popup.on('onManualIssueAdded', function (issue) {
+ that.addIssue(issue);
});
popup.render();
},
diff --git a/server/sonar-web/src/main/js/libs/third-party/backbone-super.js b/server/sonar-web/src/main/js/libs/third-party/backbone-super.js
new file mode 100644
index 00000000000..9562638918e
--- /dev/null
+++ b/server/sonar-web/src/main/js/libs/third-party/backbone-super.js
@@ -0,0 +1,111 @@
+// This is a plugin, constructed from parts of Backbone.js and John Resig's inheritance script.
+// (See http://backbonejs.org, http://ejohn.org/blog/simple-javascript-inheritance/)
+// No credit goes to me as I did absolutely nothing except patch these two together.
+(function(root, factory) {
+
+ // Set up Backbone appropriately for the environment. Start with AMD.
+ if (typeof define === 'function' && define.amd) {
+ define(['underscore', 'backbone'], function(_, Backbone) {
+ // Export global even in AMD case in case this script is loaded with
+ // others that may still expect a global Backbone.
+ factory( _, Backbone);
+ });
+
+ // Next for Node.js or CommonJS.
+ } else if (typeof exports !== 'undefined' && typeof require === 'function') {
+ var _ = require('underscore'),
+ Backbone = require('backbone');
+ factory(_, Backbone);
+
+ // Finally, as a browser global.
+ } else {
+ factory(root._, root.Backbone);
+ }
+
+}(this, function factory(_, Backbone) {
+ Backbone.Model.extend = Backbone.Collection.extend = Backbone.Router.extend = Backbone.View.extend = function(protoProps, classProps) {
+ var child = inherits(this, protoProps, classProps);
+ child.extend = this.extend;
+ return child;
+ };
+ var unImplementedSuper = function(method){throw "Super does not implement this method: " + method;};
+
+ var fnTest = /\b_super\b/;
+
+ var makeWrapper = function(parentProto, name, fn) {
+ var wrapper = function() {
+ var tmp = this._super;
+
+ // Add a new ._super() method that is the same method
+ // but on the super-class
+ this._super = parentProto[name] || unImplementedSuper(name);
+
+ // The method only need to be bound temporarily, so we
+ // remove it when we're done executing
+ var ret;
+ try {
+ ret = fn.apply(this, arguments);
+ } finally {
+ this._super = tmp;
+ }
+ return ret;
+ };
+
+ //we must move properties from old function to new
+ for (var prop in fn) {
+ wrapper[prop] = fn[prop];
+ delete fn[prop];
+ }
+
+ return wrapper;
+ };
+
+ var ctor = function(){}, inherits = function(parent, protoProps, staticProps) {
+ var child, parentProto = parent.prototype;
+
+ // The constructor function for the new subclass is either defined by you
+ // (the "constructor" property in your `extend` definition), or defaulted
+ // by us to simply call the parent's constructor.
+ if (protoProps && protoProps.hasOwnProperty('constructor')) {
+ child = protoProps.constructor;
+ } else {
+ child = function(){ return parent.apply(this, arguments); };
+ }
+
+ // Inherit class (static) properties from parent.
+ _.extend(child, parent, staticProps);
+
+ // Set the prototype chain to inherit from `parent`, without calling
+ // `parent`'s constructor function.
+ ctor.prototype = parentProto;
+ child.prototype = new ctor();
+
+ // Add prototype properties (instance properties) to the subclass,
+ // if supplied.
+ if (protoProps) {
+ _.extend(child.prototype, protoProps);
+
+ // Copy the properties over onto the new prototype
+ for (var name in protoProps) {
+ // Check if we're overwriting an existing function
+ if (typeof protoProps[name] == "function" && fnTest.test(protoProps[name])) {
+ child.prototype[name] = makeWrapper(parentProto, name, protoProps[name]);
+ }
+ }
+ }
+
+ // Add static properties to the constructor function, if supplied.
+ if (staticProps) _.extend(child, staticProps);
+
+ // Correctly set child's `prototype.constructor`.
+ child.prototype.constructor = child;
+
+ // Set a convenience property in case the parent's prototype is needed later.
+ child.__super__ = parentProto;
+
+ return child;
+ };
+
+ return inherits;
+}));
+
diff --git a/server/sonar-web/src/main/less/components/issues.less b/server/sonar-web/src/main/less/components/issues.less
index 2aa096c1ba9..ed6db933ad5 100644
--- a/server/sonar-web/src/main/less/components/issues.less
+++ b/server/sonar-web/src/main/less/components/issues.less
@@ -91,8 +91,12 @@
.issue-rule {
padding: 0 3px;
- background-color: fade(@blue, 30%);
+ background: fade(@blue, 30%);
opacity: 0.5;
+
+ &:hover {
+ background: fade(@blue, 30%);
+ }
}
.issue-component {
@@ -121,15 +125,10 @@
}
.issue-meta-list {
- .clearfix;
padding-left: @leftPadding;
- font-size: 0;
}
.issue-meta {
- display: inline-block;
- vertical-align: top;
- margin-right: 10px;
line-height: 1.5;
font-size: @smallFontSize;
}
@@ -157,14 +156,6 @@
.text-ellipsis;
}
-.issue-action {
- border-bottom: none;
-}
-
-.issue-action + .issue-action {
- margin-left: 4px;
-}
-
.issue-changelog {
max-width: 540px;
max-height: 320px;
diff --git a/server/sonar-web/src/main/less/components/panels.less b/server/sonar-web/src/main/less/components/panels.less
index 44c2e82b69d..55c32ad5de1 100644
--- a/server/sonar-web/src/main/less/components/panels.less
+++ b/server/sonar-web/src/main/less/components/panels.less
@@ -25,7 +25,7 @@
}
.panel + .panel {
- margin-top: 20px;
+ margin-top: 10px;
padding-top: 20px;
border-top: 1px solid @barBorderColor;
}
diff --git a/server/sonar-web/src/main/less/init/forms.less b/server/sonar-web/src/main/less/init/forms.less
index 656491eb0b6..81e7bb940e5 100644
--- a/server/sonar-web/src/main/less/init/forms.less
+++ b/server/sonar-web/src/main/less/init/forms.less
@@ -139,6 +139,34 @@ input[type=button] {
color: @baseFontColor;
}
+.button-link {
+ display: inline;
+ height: auto;
+ margin: 0;
+ padding: 0;
+ border: none;
+ background: transparent;
+ color: @darkBlue;
+ font-weight: 400;
+ font-size: inherit;
+ line-height: inherit;
+ .trans;
+
+ &:hover, &:active, &:focus {
+ background: transparent;
+ color: @blue;
+ }
+
+ &[disabled],
+ &[disabled]:hover,
+ &[disabled]:active,
+ &[disabled]:focus {
+ color: @secondFontColor;
+ background: transparent;
+ cursor: default;
+ }
+}
+
.button-group {
display: inline-block;
vertical-align: middle;
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/groups_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/groups_controller.rb
index 51a6a8063ba..3c7c9873495 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/groups_controller.rb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/groups_controller.rb
@@ -23,175 +23,7 @@ class GroupsController < ApplicationController
before_filter :admin_required
def index
- @groups = Group.find(:all, :order => 'name')
- if params[:id]
- @group = Group.find(params[:id])
- else
- @group = Group.new
- end
- end
-
- def create_form
- @group = Group.new
- render :partial => 'groups/create_form'
- end
-
- def edit_form
- require_parameters :id
- @group = Group.find(params[:id])
- render :partial => 'groups/edit_form'
- end
-
- def create
- verify_post_request
- group = Group.new(params[:group])
- if group.save
- flash[:notice] = 'The new group is created.'
- render :text => 'ok', :status => 200
- else
- @group = group
- @errors = []
- group.errors.full_messages.each{|msg| @errors<<msg}
- render :partial => 'groups/create_form', :status => 400
- end
- end
-
- def update
- verify_post_request
- require_parameters :id
-
- @group = Group.find(params[:id])
- if @group.update_attributes(params[:group])
- flash[:notice] = 'Group is updated.'
- render :text => 'ok', :status => 200
- else
- @errors = []
- @group.errors.full_messages.each{|msg| @errors<<msg}
- render :partial => 'groups/edit_form', :status => 400
- end
- end
-
- def delete
- verify_post_request
- require_parameters :id
- group = Group.find(params[:id])
- call_backend do
- Internal.permission_templates.removeGroupFromTemplates(group.name)
- if group.destroy
- flash[:notice] = 'Group is deleted.'
- end
- end
- to_index(group.errors, nil)
- end
-
- # TO BE REMOVED ?
- def select_user
- @group = Group.find(params[:id])
- render :partial => 'groups/select_user'
- end
-
- # TO BE REMOVED ?
- def set_users
- @group = Group.find(params[:id])
- if @group.set_users(params[:users])
- flash[:notice] = 'Group is updated.'
- end
-
- redirect_to(:action => 'index')
- end
-
-
- # Used for selection of group members
- #
- # GET /groups/search_users?group=<group_name>&page=1&pageSize=10
- #
- #
- def search_users
- require_parameters :group, :page, :pageSize
-
- group = Group.first(:conditions => {:name => params[:group]})
- group_id = group.id
- selected = params[:selected]||'all'
- query = params[:query]
- page_id = params[:page].to_i
- page_size = [params[:pageSize].to_i, 1000].min
-
- conditions = ['users.active=?']
- condition_values = [true]
- if selected=='selected'
- conditions << "groups_users.group_id=?"
- condition_values << group_id
- elsif selected=='deselected'
- conditions << "groups_users.group_id is null"
- end
- if query
- conditions << "users.name like ?"
- condition_values << "%#{query}%"
- end
-
- users = User.find(:all,
- :select => 'users.id,users.name,users.login,groups_users.group_id',
- :joins => "left join groups_users on users.id=groups_users.user_id and groups_users.group_id=#{group_id}",
- :conditions => [conditions.join(' and ')].concat(condition_values),
- :offset => (page_id-1) * page_size,
- :limit => page_size + 1,
- :order => 'users.name')
-
- more = false
- if users.size>page_size
- users = users[0...page_size]
- more = true
- end
-
- respond_to do |format|
- format.json {
- render :json => {
- :more => more,
- :results => users.map {|user| {:id => user.id, :name => user.name, :login => user.login, :selected => (user.group_id != nil)}}
- }
- }
- end
- end
-
- def add_member
- verify_post_request
- require_parameters :group, :user
-
- user = User.find(:first, :conditions => {:login => params[:user], :active => true})
- group = Group.first(:conditions => {:name => params[:group]})
- status = 400
- if user && group
- group.users << user
- status = 200 if group.save
- end
- render :status => status, :text => '{}'
- end
-
- def remove_member
- verify_post_request
- require_parameters :group, :user
-
- user = User.find(:first, :conditions => {:login => params[:user], :active => true})
- user_id = user.id
- group = Group.first(:conditions => {:name => params[:group]})
- status = 400
- if group
- user_from_group = group.users.find(user_id)
- if user_from_group
- group.users.delete(user_from_group)
- status = 200 if group.save
- else
- status = 200
- end
- end
- render :status => status, :text => '{}'
- end
-
- private
- def to_index(errors, id)
- flash[:error] = errors.full_messages.join("<br/>\n") unless errors.empty?
- redirect_to(:action => 'index', :id => id)
end
end
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb
index f5d868da748..c1b98d59ad0 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/component_issues/index.html.erb
@@ -6,9 +6,9 @@
<script>
var config = {
- resource: '<%= @resource.uuid -%>',
- resourceQualifier: '<%= @resource.qualifier -%>',
- resourceName: '<%= @resource.name -%>',
- periodDate: <% if @period %>'<%= @snapshot.period_datetime(@period) -%>'<% else %>null<% end %>
+ resource: '<%= escape_javascript @resource.uuid -%>',
+ resourceQualifier: '<%= escape_javascript @resource.qualifier -%>',
+ resourceName: '<%= escape_javascript @resource.name -%>',
+ periodDate: <% if @period %>'<%= escape_javascript @snapshot.period_datetime(@period) -%>'<% else %>null<% end %>
};
</script>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_create_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_create_form.html.erb
deleted file mode 100644
index 1e4036728b9..00000000000
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_create_form.html.erb
+++ /dev/null
@@ -1,34 +0,0 @@
-<% form_for :group, @group, :url => { :action => 'create', :id => @group.id}, :html => { :id =>'group_form'} do |f| %>
- <fieldset>
- <div class="modal-head">
- <h2>Add new group</h2>
- </div>
-
- <div class="modal-body">
- <% if @errors
- @errors.each do |error|
- %>
- <p class="error"><%= h error -%></p>
- <% end
- end
- %>
- <div class="modal-field">
- <label for="group[]">Name:<em class="mandatory">*</em></label>
- <%= f.text_field :name, :size => 25 %><br/>
- <span class="desc">Ex: my-group</span>
- </div>
- <div class="modal-field">
- <label for="group[]">Description:</label>
- <%= f.text_area :description, :rows => 3, :cols => 25 %>
- </div>
- </div>
-
- <div class="modal-foot">
- <%= submit_tag 'Create' %>
- <%= link_to 'Cancel', { :controller => 'groups', :action => 'index', :id => nil}, { :class => 'action' } %><br/>
- </div>
- </fieldset>
-<% end %>
-<script>
- $j("#group_form").modalForm();
-</script> \ No newline at end of file
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_edit_form.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_edit_form.html.erb
deleted file mode 100644
index cc649f85432..00000000000
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_edit_form.html.erb
+++ /dev/null
@@ -1,34 +0,0 @@
-<% form_for :group, @group, :url => { :action => 'update', :id => @group.id}, :html => { :id =>'group_form'} do |f| %>
- <fieldset>
- <div class="modal-head">
- <h2>Edit group: <%= h @group.name_was -%></h2>
- </div>
-
- <div class="modal-body">
- <% if @errors
- @errors.each do |error|
- %>
- <p class="error"><%= h error -%></p>
- <% end
- end
- %>
- <div class="modal-field">
- <label for="group[]">Name:<em class="mandatory">*</em></label>
- <%= f.text_field :name, :size => 25 %><br/>
- <span class="desc">Ex: my-group</span>
- </div>
- <div class="modal-field">
- <label for="group[]">Description:</label>
- <%= f.text_area :description, :rows => 3, :cols => 25 %>
- </div>
- </div>
-
- <div class="modal-foot">
- <%= submit_tag 'Save' -%>
- <%= link_to 'Cancel', { :controller => 'groups', :action => 'index', :id => nil}, { :class => 'action' } %><br/>
- </div>
- </fieldset>
-<% end %>
-<script>
- $j("#group_form").modalForm();
-</script>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_select_user.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_select_user.html.erb
deleted file mode 100644
index edaa5ee2a55..00000000000
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/_select_user.html.erb
+++ /dev/null
@@ -1,36 +0,0 @@
-<div class="modal-head">
- <h2>Group: <%= h @group.name -%></h2>
-</div>
-
-<div class="modal-body">
- <div id="select-list-group"></div>
-</div>
-
-<div class="modal-foot">
- <%= link_to 'Close', { :controller => 'groups', :action => 'index', :id => nil}, { :class => 'action' } %><br/>
-</div>
-
-<script>
- var selectList = new SelectList({
- el: '#select-list-group',
- width: '100%',
- format: function (item) { return item.name + ' <div class="note">' + item.login + '</div>'; },
- searchUrl: baseUrl + '/groups/search_users?group=<%= @group.name -%>',
- selectUrl: baseUrl + '/groups/add_member',
- deselectUrl: baseUrl + '/groups/remove_member',
- extra: {
- group: '<%= @group.name -%>'
- },
- selectParameter: 'user',
- selectParameterValue: 'login',
- labels: {
- selected: 'Members',
- deselected: 'Non-members',
- all: 'All'
- },
- tooltips: {
- select: 'Click to add this user to the group <%= h @group.name -%>',
- deselect: 'Click to remove this member from the group <%= h @group.name -%>'
- }
- });
-</script>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb
index fbf1a00fa7e..fedf3bd424c 100644
--- a/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb
+++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/groups/index.html.erb
@@ -1,65 +1,6 @@
-<% content_for :script do %>
- <script>require(['components/common/select-list']);</script>
-<% end %>
-
-<div class="page">
- <header class="page-header">
- <h1 class="page-title"><%= message('user_groups.page') -%></h1>
- <% if is_admin? %>
- <div class="page-actions">
- <a id="link-create-group" href="<%= ApplicationController.root_context -%>/groups/create_form" class="open-modal link-action">Add new group</a>
- </div>
- <% end %>
- <p class="page-description"><%= message('user_groups.page.description') -%> </p>
- </header>
-
-
- <table width="100%">
- <tr>
- <td valign="top">
-
- <table class="data width100 sortable" id="groups">
- <thead>
- <tr>
- <th class="text-left sortfirstasc"><a>Name</a></th>
- <th class="text-left"><a>Description</a></th>
- <th class="text-left"><a>Members</a></th>
- <th class="text-right nosort" nowrap><a>Operations</a></th>
- </tr>
- </thead>
- <tbody>
- <tr id="group-anyone">
- <td class="text-left"><%= h 'Anyone' -%></td>
- <td class="text-left" style="word-break:break-all"><%= message('user_groups.anyone.description') -%></td>
- <td class="text-left">&nbsp;</td>
- <td>&nbsp;</td>
- </tr>
- <% @groups.each do |group| %>
- <tr id="group-<%= group.name.parameterize -%>">
- <td class="text-left"><%= h group.name -%></td>
- <td class="text-left" style="word-break:break-all"><%= h group.description -%></td>
- <td class="text-left">
- <span id="count-<%= group.name.parameterize -%>"><%= group.users.count -%></span>
- (<a id="select-<%= group.name.parameterize -%>" class="open-modal link-action" href="<%= ApplicationController.root_context -%>/groups/select_user/<%= group.id -%>">select</a>)
- </td>
- <td class="text-right">
- <a id='edit-<%= group.name.parameterize -%>' class='open-modal link-action' href="<%= ApplicationController.root_context -%>/groups/edit_form/<%= group.id -%>">Edit</a>
- &nbsp;
- <%= link_to_action message('delete'), "#{ApplicationController.root_context}/groups/delete/#{group.id}",
- :class => 'link-action link-red',
- :id => "delete-#{group.name.parameterize}",
- :confirm_button => message('delete'),
- :confirm_title => 'Delete group: ' + group.name,
- :confirm_msg => 'Are you sure that you want to delete this group? Members will not be deleted.',
- :confirm_msg_params => [group.name]
- -%>
- </td>
- </tr>
- <% end %>
- </tbody>
- </table>
- <script>jQuery('#groups').sortable();</script>
- </td>
- </tr>
- </table>
-</div>
+<div id="groups"></div>
+<script>
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+</script>
diff --git a/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/916_feed_metrics_booleans.rb b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/916_feed_metrics_booleans.rb
new file mode 100644
index 00000000000..347164f04ef
--- /dev/null
+++ b/server/sonar-web/src/main/webapp/WEB-INF/db/migrate/916_feed_metrics_booleans.rb
@@ -0,0 +1,31 @@
+#
+# SonarQube, open source software quality management tool.
+# Copyright (C) 2008-2014 SonarSource
+# mailto:contact AT sonarsource DOT com
+#
+# SonarQube is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 3 of the License, or (at your option) any later version.
+#
+# SonarQube is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+
+#
+# SonarQube 5.2
+# SONAR-6571
+#
+class FeedMetricsBooleans < ActiveRecord::Migration
+
+ def self.up
+ execute_java_migration('org.sonar.server.db.migrations.v52.FeedMetricsBooleans')
+ end
+
+end
diff --git a/server/sonar-web/src/test/js/groups-spec.js b/server/sonar-web/src/test/js/groups-spec.js
new file mode 100644
index 00000000000..ef21e8a8fea
--- /dev/null
+++ b/server/sonar-web/src/test/js/groups-spec.js
@@ -0,0 +1,355 @@
+/* globals casper: false */
+var lib = require('../lib'),
+ testName = lib.testName('Groups');
+
+lib.initMessages();
+lib.changeWorkingDirectory('groups-spec');
+lib.configureCasper();
+
+casper.test.begin(testName('List'), 7, function (test) {
+ casper
+ .start(lib.buildUrl('groups'), function () {
+ lib.setDefaultViewport();
+ lib.mockRequestFromFile('/api/usergroups/search', 'search.json');
+ })
+
+ .then(function () {
+ casper.evaluate(function () {
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+ });
+ })
+
+ .then(function () {
+ casper.waitForText('sonar-users');
+ })
+
+ .then(function () {
+ test.assertExists('#groups-list ul');
+ test.assertElementCount('#groups-list li[data-id]', 2);
+ test.assertSelectorContains('#groups-list .js-group-name', 'sonar-users');
+ test.assertSelectorContains('#groups-list .js-group-description',
+ 'Any new users created will automatically join this group');
+ test.assertElementCount('#groups-list .js-group-update', 2);
+ test.assertElementCount('#groups-list .js-group-delete', 2);
+ test.assertSelectorContains('#groups-list-footer', '2/2');
+ })
+
+ .then(function () {
+ lib.sendCoverage();
+ })
+ .run(function () {
+ test.done();
+ });
+});
+
+
+casper.test.begin(testName('Search'), 4, function (test) {
+ casper
+ .start(lib.buildUrl('groups'), function () {
+ lib.setDefaultViewport();
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search.json');
+ })
+
+ .then(function () {
+ casper.evaluate(function () {
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+ });
+ })
+
+ .then(function () {
+ casper.waitForText('sonar-users');
+ })
+
+ .then(function () {
+ test.assertElementCount('#groups-list li[data-id]', 2);
+ lib.clearRequestMock(this.searchMock);
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search-filtered.json',
+ { data: { q: 'adm' } });
+ casper.evaluate(function () {
+ jQuery('#groups-search-query').val('adm');
+ });
+ casper.click('#groups-search-submit');
+ casper.waitForSelectorTextChange('#groups-list-footer');
+ })
+
+ .then(function () {
+ test.assertElementCount('#groups-list li[data-id]', 1);
+ lib.clearRequestMock(this.searchMock);
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search.json');
+ casper.evaluate(function () {
+ jQuery('#groups-search-query').val('');
+ });
+ casper.click('#groups-search-submit');
+ casper.waitForSelectorTextChange('#groups-list-footer');
+ })
+
+ .then(function () {
+ test.assertElementCount('#groups-list li[data-id]', 2);
+ test.assert(casper.evaluate(function () {
+ return jQuery('#groups-search-query').val() === '';
+ }));
+ })
+
+ .then(function () {
+ lib.sendCoverage();
+ })
+ .run(function () {
+ test.done();
+ });
+});
+
+
+casper.test.begin(testName('Show More'), 4, function (test) {
+ casper
+ .start(lib.buildUrl('groups'), function () {
+ lib.setDefaultViewport();
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search-big-1.json');
+ })
+
+ .then(function () {
+ casper.evaluate(function () {
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+ });
+ })
+
+ .then(function () {
+ casper.waitForText('sonar-users');
+ })
+
+ .then(function () {
+ test.assertElementCount('#groups-list li[data-id]', 1);
+ test.assertSelectorContains('#groups-list-footer', '1/2');
+ lib.clearRequestMock(this.searchMock);
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search-big-2.json', { data: { p: '2' } });
+ casper.click('#groups-fetch-more');
+ casper.waitForSelectorTextChange('#groups-list-footer');
+ })
+
+ .then(function () {
+ test.assertElementCount('#groups-list li[data-id]', 2);
+ test.assertSelectorContains('#groups-list-footer', '2/2');
+ })
+
+ .then(function () {
+ lib.sendCoverage();
+ })
+ .run(function () {
+ test.done();
+ });
+});
+
+
+casper.test.begin(testName('Show Users'), 2, function (test) {
+ casper
+ .start(lib.buildUrl('groups'), function () {
+ lib.setDefaultViewport();
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search.json');
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/users*', 'users.json');
+ })
+
+ .then(function () {
+ casper.evaluate(function () {
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+ });
+ })
+
+ .then(function () {
+ casper.waitForText('sonar-users');
+ })
+
+ .then(function () {
+ test.assertTextDoesntExist('Bob');
+ casper.click('[data-id="1"] .js-group-users');
+ casper.waitForText('Bob');
+ })
+
+ .then(function () {
+ test.assertTextExist('John');
+ })
+
+ .then(function () {
+ lib.sendCoverage();
+ })
+ .run(function () {
+ test.done();
+ });
+});
+
+
+casper.test.begin(testName('Create'), 4, function (test) {
+ casper
+ .start(lib.buildUrl('groups'), function () {
+ lib.setDefaultViewport();
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search.json');
+ this.createMock = lib.mockRequestFromFile('/api/usergroups/create', 'error.json', { status: 400 });
+ })
+
+ .then(function () {
+ casper.evaluate(function () {
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+ jQuery.ajaxSetup({ dataType: 'json' });
+ });
+ })
+
+ .then(function () {
+ casper.waitForText('sonar-users');
+ })
+
+ .then(function () {
+ test.assertElementCount('#groups-list li[data-id]', 2);
+ casper.click('#groups-create');
+ casper.waitForSelector('#create-group-form');
+ })
+
+ .then(function () {
+ casper.click('#create-group-submit');
+ casper.waitForSelector('.alert.alert-danger');
+ })
+
+ .then(function () {
+ lib.clearRequestMock(this.searchMock);
+ lib.mockRequestFromFile('/api/usergroups/search', 'search-created.json');
+ lib.clearRequestMock(this.createMock);
+ lib.mockRequest('/api/usergroups/create', '{}',
+ { data: { name: 'name', description: 'description' } });
+ casper.evaluate(function () {
+ jQuery('#create-group-name').val('name');
+ jQuery('#create-group-description').val('description');
+ });
+ casper.click('#create-group-submit');
+ casper.waitForSelectorTextChange('#groups-list-footer');
+ })
+
+ .then(function () {
+ test.assertElementCount('#groups-list li[data-id]', 3);
+ test.assertSelectorContains('#groups-list .js-group-name', 'name');
+ test.assertSelectorContains('#groups-list .js-group-description', 'description');
+ })
+
+ .then(function () {
+ lib.sendCoverage();
+ })
+ .run(function () {
+ test.done();
+ });
+});
+
+
+casper.test.begin(testName('Update'), 2, function (test) {
+ casper
+ .start(lib.buildUrl('groups'), function () {
+ lib.setDefaultViewport();
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search.json');
+ this.updateMock = lib.mockRequestFromFile('/api/usergroups/update', 'error.json', { status: 400 });
+ })
+
+ .then(function () {
+ casper.evaluate(function () {
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+ jQuery.ajaxSetup({ dataType: 'json' });
+ });
+ })
+
+ .then(function () {
+ casper.waitForText('sonar-users');
+ })
+
+ .then(function () {
+ casper.click('[data-id="2"] .js-group-update');
+ casper.waitForSelector('#create-group-form');
+ })
+
+ .then(function () {
+ casper.click('#create-group-submit');
+ casper.waitForSelector('.alert.alert-danger');
+ })
+
+ .then(function () {
+ lib.clearRequestMock(this.searchMock);
+ lib.mockRequestFromFile('/api/usergroups/search', 'search-updated.json');
+ lib.clearRequestMock(this.updateMock);
+ lib.mockRequest('/api/usergroups/update', '{}',
+ { data: { id: '2', name: 'guys', description: 'cool guys' } });
+ casper.evaluate(function () {
+ jQuery('#create-group-name').val('guys');
+ jQuery('#create-group-description').val('cool guys');
+ });
+ casper.click('#create-group-submit');
+ casper.waitForText('guys');
+ })
+
+ .then(function () {
+ test.assertSelectorContains('[data-id="2"] .js-group-name', 'guys');
+ test.assertSelectorContains('[data-id="2"] .js-group-description', 'cool guys');
+ })
+
+ .then(function () {
+ lib.sendCoverage();
+ })
+ .run(function () {
+ test.done();
+ });
+});
+
+
+casper.test.begin(testName('Delete'), 1, function (test) {
+ casper
+ .start(lib.buildUrl('groups'), function () {
+ lib.setDefaultViewport();
+ this.searchMock = lib.mockRequestFromFile('/api/usergroups/search', 'search.json');
+ this.updateMock = lib.mockRequestFromFile('/api/usergroups/delete', 'error.json', { status: 400 });
+ })
+
+ .then(function () {
+ casper.evaluate(function () {
+ require(['apps/groups/app'], function (App) {
+ App.start({ el: '#groups' });
+ });
+ jQuery.ajaxSetup({ dataType: 'json' });
+ });
+ })
+
+ .then(function () {
+ casper.waitForText('sonar-users');
+ })
+
+ .then(function () {
+ casper.click('[data-id="1"] .js-group-delete');
+ casper.waitForSelector('#delete-group-form');
+ })
+
+ .then(function () {
+ casper.click('#delete-group-submit');
+ casper.waitForSelector('.alert.alert-danger');
+ })
+
+ .then(function () {
+ lib.clearRequestMock(this.updateMock);
+ lib.mockRequest('/api/usergroups/delete', '{}', { data: { id: '1'} });
+ casper.click('#delete-group-submit');
+ casper.waitWhileSelector('[data-id="1"]');
+ })
+
+ .then(function () {
+ test.assert(true);
+ })
+
+ .then(function () {
+ lib.sendCoverage();
+ })
+ .run(function () {
+ test.done();
+ });
+});
diff --git a/server/sonar-web/src/test/json/groups-spec/error.json b/server/sonar-web/src/test/json/groups-spec/error.json
new file mode 100644
index 00000000000..dc1b261128c
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/error.json
@@ -0,0 +1,7 @@
+{
+ "errors": [
+ {
+ "msg": "Some error message"
+ }
+ ]
+}
diff --git a/server/sonar-web/src/test/json/groups-spec/search-big-1.json b/server/sonar-web/src/test/json/groups-spec/search-big-1.json
new file mode 100644
index 00000000000..654742be995
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/search-big-1.json
@@ -0,0 +1,13 @@
+{
+ "total": 2,
+ "p": 1,
+ "ps": 1,
+ "groups": [
+ {
+ "id": "1",
+ "name": "sonar-users",
+ "description": "Any new users created will automatically join this group",
+ "membersCount": 3
+ }
+ ]
+}
diff --git a/server/sonar-web/src/test/json/groups-spec/search-big-2.json b/server/sonar-web/src/test/json/groups-spec/search-big-2.json
new file mode 100644
index 00000000000..9d8a35bd3b6
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/search-big-2.json
@@ -0,0 +1,13 @@
+{
+ "total": 2,
+ "p": 2,
+ "ps": 1,
+ "groups": [
+ {
+ "id": "2",
+ "name": "sonar-administrators",
+ "description": "System administrators",
+ "membersCount": 1
+ }
+ ]
+}
diff --git a/server/sonar-web/src/test/json/groups-spec/search-created.json b/server/sonar-web/src/test/json/groups-spec/search-created.json
new file mode 100644
index 00000000000..1222b0dc009
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/search-created.json
@@ -0,0 +1,25 @@
+{
+ "total": 3,
+ "p": 1,
+ "ps": 50,
+ "groups": [
+ {
+ "id": "1",
+ "name": "sonar-users",
+ "description": "Any new users created will automatically join this group",
+ "membersCount": 3
+ },
+ {
+ "id": "2",
+ "name": "sonar-administrators",
+ "description": "System administrators",
+ "membersCount": 1
+ },
+ {
+ "id": "3",
+ "name": "name",
+ "description": "description",
+ "membersCount": 0
+ }
+ ]
+}
diff --git a/server/sonar-web/src/test/json/groups-spec/search-filtered.json b/server/sonar-web/src/test/json/groups-spec/search-filtered.json
new file mode 100644
index 00000000000..58a0ead4a40
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/search-filtered.json
@@ -0,0 +1,13 @@
+{
+ "total": 1,
+ "p": 1,
+ "ps": 50,
+ "groups": [
+ {
+ "id": "2",
+ "name": "sonar-administrators",
+ "description": "System administrators",
+ "membersCount": 1
+ }
+ ]
+}
diff --git a/server/sonar-web/src/test/json/groups-spec/search-updated.json b/server/sonar-web/src/test/json/groups-spec/search-updated.json
new file mode 100644
index 00000000000..ed1484f245d
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/search-updated.json
@@ -0,0 +1,19 @@
+{
+ "total": 2,
+ "p": 1,
+ "ps": 50,
+ "groups": [
+ {
+ "id": "1",
+ "name": "sonar-users",
+ "description": "Any new users created will automatically join this group",
+ "membersCount": 3
+ },
+ {
+ "id": "2",
+ "name": "guys",
+ "description": "cool guys",
+ "membersCount": 1
+ }
+ ]
+}
diff --git a/server/sonar-web/src/test/json/groups-spec/search.json b/server/sonar-web/src/test/json/groups-spec/search.json
new file mode 100644
index 00000000000..a347403c5ae
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/search.json
@@ -0,0 +1,19 @@
+{
+ "total": 2,
+ "p": 1,
+ "ps": 50,
+ "groups": [
+ {
+ "id": "1",
+ "name": "sonar-users",
+ "description": "Any new users created will automatically join this group",
+ "membersCount": 3
+ },
+ {
+ "id": "2",
+ "name": "sonar-administrators",
+ "description": "System administrators",
+ "membersCount": 1
+ }
+ ]
+}
diff --git a/server/sonar-web/src/test/json/groups-spec/users.json b/server/sonar-web/src/test/json/groups-spec/users.json
new file mode 100644
index 00000000000..dfb28ec4555
--- /dev/null
+++ b/server/sonar-web/src/test/json/groups-spec/users.json
@@ -0,0 +1,17 @@
+{
+ "users": [
+ {
+ "login": "bob",
+ "name": "Bob",
+ "selected": true
+ },
+ {
+ "login": "john",
+ "name": "John",
+ "selected": true
+ }
+ ],
+ "p": 1,
+ "ps": 100,
+ "total": 2
+}
diff --git a/server/sonar-web/src/test/views/groups.jade b/server/sonar-web/src/test/views/groups.jade
new file mode 100644
index 00000000000..ddf0a29c6a3
--- /dev/null
+++ b/server/sonar-web/src/test/views/groups.jade
@@ -0,0 +1,5 @@
+extends layouts/main
+
+block body
+ #content
+ #groups
diff --git a/server/sonar-web/src/test/views/layouts/main.jade b/server/sonar-web/src/test/views/layouts/main.jade
index 901a1042055..ccc08eb3ad8 100644
--- a/server/sonar-web/src/test/views/layouts/main.jade
+++ b/server/sonar-web/src/test/views/layouts/main.jade
@@ -10,6 +10,7 @@ html
script(src='/js/libs/third-party/latinize.js')
script(src='/js/libs/third-party/underscore.js')
script(src='/js/libs/third-party/backbone.js')
+ script(src='/js/libs/third-party/backbone-super.js')
script(src='/js/libs/third-party/backbone.marionette.js')
script(src='/js/libs/third-party/handlebars.js')
script(src='/js/libs/third-party/underscore.js')
diff --git a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
index c41ce080065..14455532309 100644
--- a/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
+++ b/sonar-batch-protocol/src/main/java/org/sonar/batch/protocol/output/BatchReportReader.java
@@ -19,14 +19,12 @@
*/
package org.sonar.batch.protocol.output;
-import org.sonar.batch.protocol.ProtobufUtil;
-import org.sonar.batch.protocol.output.BatchReport.Issues;
-
-import javax.annotation.CheckForNull;
-
import java.io.File;
import java.util.Collections;
import java.util.List;
+import javax.annotation.CheckForNull;
+import org.sonar.batch.protocol.ProtobufUtil;
+import org.sonar.batch.protocol.output.BatchReport.Issues;
public class BatchReportReader {
@@ -161,7 +159,7 @@ public class BatchReportReader {
return null;
}
- private boolean doesFileExists(File file) {
+ private static boolean doesFileExists(File file) {
return file.exists() && file.isFile();
}
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java b/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java
index 9118dc3450e..d10f6ba5fab 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/DefaultFileLinesContext.java
@@ -23,6 +23,7 @@ import com.google.common.base.Objects;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
+import java.util.Map;
import org.sonar.api.batch.SonarIndex;
import org.sonar.api.measures.FileLinesContext;
import org.sonar.api.measures.Measure;
@@ -33,8 +34,6 @@ import org.sonar.api.resources.ResourceUtils;
import org.sonar.api.utils.KeyValueFormat;
import org.sonar.api.utils.KeyValueFormat.Converter;
-import java.util.Map;
-
public class DefaultFileLinesContext implements FileLinesContext {
private final SonarIndex index;
@@ -143,7 +142,7 @@ public class DefaultFileLinesContext implements FileLinesContext {
* @see #loadData(String, Converter)
* @see #save()
*/
- private boolean shouldSave(Map<Integer, Object> lines) {
+ private static boolean shouldSave(Map<Integer, Object> lines) {
return !(lines instanceof ImmutableMap);
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/compute/AbstractNewCoverageFileAnalyzer.java b/sonar-batch/src/main/java/org/sonar/batch/compute/AbstractNewCoverageFileAnalyzer.java
index 446c0820244..6f17ffc0341 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/compute/AbstractNewCoverageFileAnalyzer.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/compute/AbstractNewCoverageFileAnalyzer.java
@@ -175,7 +175,7 @@ public abstract class AbstractNewCoverageFileAnalyzer implements Decorator {
context.saveMeasure(newUncoveredConditions);
}
- private Map<Integer, Integer> parseCountByLine(@Nullable Measure measure) {
+ private static Map<Integer, Integer> parseCountByLine(@Nullable Measure measure) {
if (measure != null && measure.hasData()) {
return KeyValueFormat.parseIntInt(measure.getData());
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/compute/CountUnresolvedIssuesDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/compute/CountUnresolvedIssuesDecorator.java
index cd57819911a..53dd6a49d51 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/compute/CountUnresolvedIssuesDecorator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/compute/CountUnresolvedIssuesDecorator.java
@@ -146,7 +146,7 @@ public class CountUnresolvedIssuesDecorator implements Decorator {
}
}
- private void saveTotalIssues(DecoratorContext context, Collection<Issue> issues) {
+ private static void saveTotalIssues(DecoratorContext context, Collection<Issue> issues) {
if (context.getMeasure(CoreMetrics.VIOLATIONS) == null) {
Collection<Measure> childrenIssues = context.getChildrenMeasures(CoreMetrics.VIOLATIONS);
Double sum = MeasureUtils.sum(true, childrenIssues);
@@ -161,7 +161,7 @@ public class CountUnresolvedIssuesDecorator implements Decorator {
}
}
- private void saveIssuesForSeverity(DecoratorContext context, RulePriority ruleSeverity, Multiset<RulePriority> severitiesBag) {
+ private static void saveIssuesForSeverity(DecoratorContext context, RulePriority ruleSeverity, Multiset<RulePriority> severitiesBag) {
Metric metric = SeverityUtils.severityToIssueMetric(ruleSeverity);
if (context.getMeasure(metric) == null) {
Collection<Measure> children = context.getChildrenMeasures(MeasuresFilters.metric(metric));
@@ -248,11 +248,11 @@ public class CountUnresolvedIssuesDecorator implements Decorator {
context.saveMeasure(measure);
}
- private void saveMeasure(DecoratorContext context, Metric metric, int value) {
+ private static void saveMeasure(DecoratorContext context, Metric metric, int value) {
context.saveMeasure(metric, (double) (value + sumChildren(context, metric)));
}
- private int sumChildren(DecoratorContext context, Metric metric) {
+ private static int sumChildren(DecoratorContext context, Metric metric) {
int sum = 0;
if (!ResourceUtils.isFile(context.getResource())) {
sum = MeasureUtils.sum(true, context.getChildrenMeasures(metric)).intValue();
@@ -260,7 +260,7 @@ public class CountUnresolvedIssuesDecorator implements Decorator {
return sum;
}
- private Multiset<RuleKey> initRules(Map<RulePriority, Multiset<RuleKey>> rulesPerSeverity, RulePriority severity) {
+ private static Multiset<RuleKey> initRules(Map<RulePriority, Multiset<RuleKey>> rulesPerSeverity, RulePriority severity) {
Multiset<RuleKey> rulesBag = rulesPerSeverity.get(severity);
if (rulesBag == null) {
rulesBag = HashMultiset.create();
@@ -289,11 +289,11 @@ public class CountUnresolvedIssuesDecorator implements Decorator {
return count;
}
- private boolean isAfter(Issue issue, @Nullable Date date) {
+ private static boolean isAfter(Issue issue, @Nullable Date date) {
return date == null || (issue.creationDate() != null && DateUtils.truncatedCompareTo(issue.creationDate(), date, Calendar.SECOND) > 0);
}
- private boolean shouldSaveNewMetrics(DecoratorContext context) {
+ private static boolean shouldSaveNewMetrics(DecoratorContext context) {
return context.getMeasure(CoreMetrics.NEW_VIOLATIONS) == null;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/compute/TimeMachineConfigurationPersister.java b/sonar-batch/src/main/java/org/sonar/batch/compute/TimeMachineConfigurationPersister.java
index 1255c64a35f..68b5e1a8330 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/compute/TimeMachineConfigurationPersister.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/compute/TimeMachineConfigurationPersister.java
@@ -74,7 +74,7 @@ public final class TimeMachineConfigurationPersister implements Decorator {
return true;
}
- private void updatePeriodParams(Snapshot snapshot, PastSnapshot pastSnapshot) {
+ private static void updatePeriodParams(Snapshot snapshot, PastSnapshot pastSnapshot) {
int periodIndex = pastSnapshot.getIndex();
snapshot.setPeriodMode(periodIndex, pastSnapshot.getMode());
snapshot.setPeriodModeParameter(periodIndex, pastSnapshot.getModeParameter());
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/DebtDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/debt/DebtDecorator.java
index c2f4c97b9a6..237f27bae67 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/debt/DebtDecorator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/debt/DebtDecorator.java
@@ -21,6 +21,12 @@
package org.sonar.batch.debt;
import com.google.common.annotations.VisibleForTesting;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorBarriers;
import org.sonar.api.batch.DecoratorContext;
@@ -47,14 +53,6 @@ import org.sonar.api.rules.RuleFinder;
import org.sonar.api.technicaldebt.batch.Characteristic;
import org.sonar.api.technicaldebt.batch.TechnicalDebtModel;
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
import static com.google.common.collect.Lists.newArrayList;
import static com.google.common.collect.Maps.newHashMap;
@@ -182,7 +180,7 @@ public final class DebtDecorator implements Decorator {
}
}
- private void saveMeasure(DecoratorContext context, Measure measure, Double value, boolean inMemory) {
+ private static void saveMeasure(DecoratorContext context, Measure measure, Double value, boolean inMemory) {
measure.setValue(value);
if (inMemory) {
measure.setPersistenceMode(PersistenceMode.MEMORY);
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java b/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java
index 7ce8c610ba5..dc95f8e8679 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/debt/DebtModelProvider.java
@@ -22,6 +22,8 @@ package org.sonar.batch.debt;
import com.google.common.base.Predicate;
import com.google.common.collect.Iterables;
+import java.util.List;
+import javax.annotation.Nullable;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.debt.DebtCharacteristic;
import org.sonar.api.batch.debt.DebtModel;
@@ -32,9 +34,6 @@ import org.sonar.api.utils.log.Profiler;
import org.sonar.core.technicaldebt.db.CharacteristicDao;
import org.sonar.core.technicaldebt.db.CharacteristicDto;
-import javax.annotation.Nullable;
-import java.util.List;
-
public class DebtModelProvider extends ProviderAdapter {
private DebtModel model;
@@ -48,7 +47,7 @@ public class DebtModelProvider extends ProviderAdapter {
return model;
}
- private DebtModel load(CharacteristicDao dao) {
+ private static DebtModel load(CharacteristicDao dao) {
DefaultDebtModel debtModel = new DefaultDebtModel();
List<CharacteristicDto> allCharacteristics = dao.selectEnabledCharacteristics();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java b/sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java
index 9d6e0fca14c..fb882a7a0eb 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/debt/IssueChangelogDebtCalculator.java
@@ -22,16 +22,6 @@ package org.sonar.batch.debt;
import com.google.common.base.Function;
import com.google.common.collect.Ordering;
-import org.apache.commons.lang.time.DateUtils;
-import org.sonar.api.batch.BatchSide;
-import org.sonar.api.issue.Issue;
-import org.sonar.api.issue.internal.DefaultIssue;
-import org.sonar.api.issue.internal.FieldDiffs;
-import org.sonar.core.issue.IssueUpdater;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
import java.util.Calendar;
import java.util.Collection;
import java.util.Collections;
@@ -39,6 +29,14 @@ import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+import org.apache.commons.lang.time.DateUtils;
+import org.sonar.api.batch.BatchSide;
+import org.sonar.api.issue.Issue;
+import org.sonar.api.issue.internal.DefaultIssue;
+import org.sonar.api.issue.internal.FieldDiffs;
+import org.sonar.core.issue.IssueUpdater;
import static com.google.common.collect.Lists.newArrayList;
@@ -82,7 +80,7 @@ public class IssueChangelogDebtCalculator {
* SONAR-5059
*/
@CheckForNull
- private Long subtractNeverNegative(@Nullable Long value, Long with) {
+ private static Long subtractNeverNegative(@Nullable Long value, @Nullable Long with) {
Long result = (value != null ? value : 0) - (with != null ? with : 0);
return result > 0 ? result : null;
}
@@ -103,7 +101,7 @@ public class IssueChangelogDebtCalculator {
return Collections.emptyList();
}
- private List<FieldDiffs> changesOnField(Collection<FieldDiffs> fieldDiffs) {
+ private static List<FieldDiffs> changesOnField(Collection<FieldDiffs> fieldDiffs) {
List<FieldDiffs> diffs = newArrayList();
for (FieldDiffs fieldDiff : fieldDiffs) {
if (fieldDiff.diffs().containsKey(IssueUpdater.TECHNICAL_DEBT)) {
@@ -114,7 +112,7 @@ public class IssueChangelogDebtCalculator {
}
@CheckForNull
- private Long newValue(FieldDiffs fieldDiffs) {
+ private static Long newValue(FieldDiffs fieldDiffs) {
for (Map.Entry<String, FieldDiffs.Diff> entry : fieldDiffs.diffs().entrySet()) {
if (entry.getKey().equals(IssueUpdater.TECHNICAL_DEBT)) {
return entry.getValue().newValueLong();
@@ -124,7 +122,7 @@ public class IssueChangelogDebtCalculator {
}
@CheckForNull
- private Long oldValue(FieldDiffs fieldDiffs) {
+ private static Long oldValue(FieldDiffs fieldDiffs) {
for (Map.Entry<String, FieldDiffs.Diff> entry : fieldDiffs.diffs().entrySet()) {
if (entry.getKey().equals(IssueUpdater.TECHNICAL_DEBT)) {
return entry.getValue().oldValueLong();
@@ -133,11 +131,11 @@ public class IssueChangelogDebtCalculator {
return null;
}
- private boolean isAfter(@Nullable Date currentDate, @Nullable Date pastDate) {
+ private static boolean isAfter(@Nullable Date currentDate, @Nullable Date pastDate) {
return pastDate == null || (currentDate != null && DateUtils.truncatedCompareTo(currentDate, pastDate, Calendar.SECOND) > 0);
}
- private boolean isLesserOrEqual(@Nullable Date currentDate, @Nullable Date pastDate) {
+ private static boolean isLesserOrEqual(@Nullable Date currentDate, @Nullable Date pastDate) {
return (currentDate != null) && (pastDate == null || (DateUtils.truncatedCompareTo(currentDate, pastDate, Calendar.SECOND) <= 0));
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java
index 9909fc47476..c334520aa79 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/debt/NewDebtDecorator.java
@@ -21,6 +21,10 @@
package org.sonar.batch.debt;
import com.google.common.collect.ImmutableList;
+import java.util.Collection;
+import java.util.Date;
+import java.util.List;
+import javax.annotation.Nullable;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorBarriers;
import org.sonar.api.batch.DecoratorContext;
@@ -39,12 +43,6 @@ import org.sonar.api.resources.Resource;
import org.sonar.batch.components.Period;
import org.sonar.batch.components.TimeMachineConfiguration;
-import javax.annotation.Nullable;
-
-import java.util.Collection;
-import java.util.Date;
-import java.util.List;
-
import static com.google.common.collect.Lists.newArrayList;
/**
@@ -109,7 +107,7 @@ public final class NewDebtDecorator implements Decorator {
return result;
}
- private boolean shouldSaveNewMetrics(DecoratorContext context) {
+ private static boolean shouldSaveNewMetrics(DecoratorContext context) {
return context.getMeasure(CoreMetrics.NEW_TECHNICAL_DEBT) == null;
}
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingDecorator.java b/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingDecorator.java
index 666ec9b633f..38dc3bd658d 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingDecorator.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingDecorator.java
@@ -22,6 +22,10 @@ package org.sonar.batch.debt;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.Lists;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.List;
+import javax.annotation.Nullable;
import org.sonar.api.batch.Decorator;
import org.sonar.api.batch.DecoratorContext;
import org.sonar.api.batch.DependedUpon;
@@ -35,12 +39,6 @@ import org.sonar.api.resources.Project;
import org.sonar.api.resources.Resource;
import org.sonar.api.resources.ResourceUtils;
-import javax.annotation.Nullable;
-
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.List;
-
/**
* Decorator that computes Sqale Rating metric
*/
@@ -95,7 +93,7 @@ public class SqaleRatingDecorator implements Decorator {
}
}
- private Measure createRatingMeasure(int rating) {
+ private static Measure createRatingMeasure(int rating) {
return new Measure(CoreMetrics.SQALE_RATING).setIntValue(rating).setData(toRatingLetter(rating));
}
@@ -132,7 +130,7 @@ public class SqaleRatingDecorator implements Decorator {
return sum;
}
- private long getMeasureValue(DecoratorContext context, Metric metric) {
+ private static long getMeasureValue(DecoratorContext context, Metric metric) {
Measure measure = context.getMeasure(metric);
if (measure != null) {
return measure.getValue().longValue();
diff --git a/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java b/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java
index bb186b177fc..ca80f62a96b 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/debt/SqaleRatingSettings.java
@@ -20,13 +20,12 @@
package org.sonar.batch.debt;
-import org.sonar.api.batch.BatchSide;
+import javax.annotation.Nullable;
import org.sonar.api.CoreProperties;
+import org.sonar.api.batch.BatchSide;
import org.sonar.api.config.Settings;
import org.sonar.api.measures.Metric;
-import javax.annotation.Nullable;
-
@BatchSide
public class SqaleRatingSettings {
@@ -76,7 +75,7 @@ public class SqaleRatingSettings {
return getMetricForKey(settings.getString(CoreProperties.SIZE_METRIC), metrics);
}
- private Metric getMetricForKey(String sizeMetricKey, Metric[] metrics) {
+ private static Metric getMetricForKey(String sizeMetricKey, Metric[] metrics) {
for (Metric metric : metrics) {
if (metric.getKey().equals(sizeMetricKey)) {
return metric;
diff --git a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
index f17b42c18db..2586d4f898a 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/issue/ModuleIssues.java
@@ -21,6 +21,7 @@ package org.sonar.batch.issue;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
+import javax.annotation.Nullable;
import org.sonar.api.batch.debt.DebtRemediationFunction;
import org.sonar.api.batch.rule.ActiveRule;
import org.sonar.api.batch.rule.ActiveRules;
@@ -35,8 +36,6 @@ import org.sonar.api.utils.Duration;
import org.sonar.api.utils.MessageException;
import org.sonar.core.issue.DefaultIssueBuilder;
-import javax.annotation.Nullable;
-
/**
* Initialize the issues raised during scan.
*/
@@ -98,7 +97,7 @@ public class ModuleIssues {
return false;
}
- private void validateRule(DefaultIssue issue, Rule rule) {
+ private static void validateRule(DefaultIssue issue, @Nullable Rule rule) {
RuleKey ruleKey = issue.ruleKey();
if (rule == null) {
throw MessageException.of(String.format("The rule '%s' does not exist.", ruleKey));
diff --git a/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java b/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java
index c886d93bf51..9a8af6d87ef 100644
--- a/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java
+++ b/sonar-batch/src/main/java/org/sonar/batch/rule/RulesProvider.java
@@ -22,6 +22,8 @@ package org.sonar.batch.rule;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ListMultimap;
+import java.util.List;
+import javax.annotation.Nullable;
import org.picocontainer.injectors.ProviderAdapter;
import org.sonar.api.batch.debt.DebtCharacteristic;
import org.sonar.api.batch.debt.DebtModel;
@@ -38,9 +40,6 @@ import org.sonar.core.rule.RuleDao;
import org.sonar.core.rule.RuleDto;
import org.sonar.core.rule.RuleParamDto;
-import javax.annotation.Nullable;
-import java.util.List;
-
/**
* Loads all enabled and non manual rules
*/
@@ -88,7 +87,7 @@ public class RulesProvider extends ProviderAdapter {
return rulesBuilder.build();
}
- private DebtCharacteristic effectiveCharacteristic(RuleDto ruleDto, RuleKey ruleKey, DefaultDebtModel debtModel) {
+ private static DebtCharacteristic effectiveCharacteristic(RuleDto ruleDto, RuleKey ruleKey, DefaultDebtModel debtModel) {
Integer subCharacteristicId = ruleDto.getSubCharacteristicId();
Integer defaultSubCharacteristicId = ruleDto.getDefaultSubCharacteristicId();
Integer effectiveSubCharacteristicId = subCharacteristicId != null ? subCharacteristicId : defaultSubCharacteristicId;
@@ -121,7 +120,7 @@ public class RulesProvider extends ProviderAdapter {
* Return true is the characteristic has not been overridden and a default characteristic is existing or
* if the characteristic has been overridden but is not disabled
*/
- private boolean hasCharacteristic(RuleDto ruleDto) {
+ private static boolean hasCharacteristic(RuleDto ruleDto) {
Integer subCharacteristicId = ruleDto.getSubCharacteristicId();
return (subCharacteristicId == null && ruleDto.getDefaultSubCharacteristicId() != null) ||
(subCharacteristicId != null && !RuleDto.DISABLED_CHARACTERISTIC_ID.equals(subCharacteristicId));
diff --git a/sonar-core/src/main/java/org/sonar/core/component/Module.java b/sonar-core/src/main/java/org/sonar/core/component/Module.java
index 25a015e55e6..1d905291e5d 100644
--- a/sonar-core/src/main/java/org/sonar/core/component/Module.java
+++ b/sonar-core/src/main/java/org/sonar/core/component/Module.java
@@ -19,6 +19,7 @@
*/
package org.sonar.core.component;
+import javax.annotation.Nullable;
import org.sonar.core.platform.ComponentContainer;
import static com.google.common.base.Preconditions.checkNotNull;
@@ -36,11 +37,11 @@ public abstract class Module {
protected abstract void configureModule();
- protected <T> T getComponentByType(Class<T> tClass) {
- return container.getComponentByType(tClass);
- }
+ protected void add(@Nullable Object... objects) {
+ if (objects == null) {
+ return;
+ }
- protected void add(Object... objects) {
for (Object object : objects) {
if (object != null) {
container.addComponent(object, true);
diff --git a/sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java b/sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java
index 63b5b9136fc..6d669eb1d40 100644
--- a/sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java
+++ b/sonar-core/src/main/java/org/sonar/core/component/SnapshotDto.java
@@ -19,6 +19,9 @@
*/
package org.sonar.core.component;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
+
public final class SnapshotDto {
/**
@@ -73,20 +76,25 @@ public final class SnapshotDto {
return this;
}
+ @CheckForNull
public Long getParentId() {
return parentId;
}
- public SnapshotDto setParentId(Long parentId) {
+ public SnapshotDto setParentId(@Nullable Long parentId) {
this.parentId = parentId;
return this;
}
+ /**
+ * Root id is null on project's snapshot
+ */
+ @CheckForNull
public Long getRootId() {
return rootId;
}
- public SnapshotDto setRootId(Long rootId) {
+ public SnapshotDto setRootId(@Nullable Long rootId) {
this.rootId = rootId;
return this;
}
@@ -118,11 +126,12 @@ public final class SnapshotDto {
return this;
}
+ @CheckForNull
public Integer getPurgeStatus() {
return purgeStatus;
}
- public SnapshotDto setPurgeStatus(Integer purgeStatus) {
+ public SnapshotDto setPurgeStatus(@Nullable Integer purgeStatus) {
this.purgeStatus = purgeStatus;
return this;
}
@@ -154,11 +163,15 @@ public final class SnapshotDto {
return this;
}
+ /**
+ * Version is only available on projects and modules
+ */
+ @CheckForNull
public String getVersion() {
return version;
}
- public SnapshotDto setVersion(String version) {
+ public SnapshotDto setVersion(@Nullable String version) {
this.version = version;
return this;
}
@@ -190,7 +203,7 @@ public final class SnapshotDto {
return this;
}
- public SnapshotDto setPeriodMode(int index, String p) {
+ public SnapshotDto setPeriodMode(int index, @Nullable String p) {
switch (index) {
case 1:
period1Mode = p;
@@ -213,6 +226,7 @@ public final class SnapshotDto {
return this;
}
+ @CheckForNull
public String getPeriodMode(int index) {
switch (index) {
case 1:
@@ -230,7 +244,7 @@ public final class SnapshotDto {
}
}
- public SnapshotDto setPeriodParam(int index, String p) {
+ public SnapshotDto setPeriodParam(int index, @Nullable String p) {
switch (index) {
case 1:
period1Param = p;
@@ -253,6 +267,7 @@ public final class SnapshotDto {
return this;
}
+ @CheckForNull
public String getPeriodModeParameter(int periodIndex) {
switch (periodIndex) {
case 1:
@@ -270,7 +285,7 @@ public final class SnapshotDto {
}
}
- public SnapshotDto setPeriodDate(int index, Long date) {
+ public SnapshotDto setPeriodDate(int index, @Nullable Long date) {
switch (index) {
case 1:
period1Date = date;
@@ -293,6 +308,7 @@ public final class SnapshotDto {
return this;
}
+ @CheckForNull
public Long getPeriodDate(int periodIndex) {
switch (periodIndex) {
case 1:
@@ -310,10 +326,6 @@ public final class SnapshotDto {
}
}
- public Long getKey() {
- return id;
- }
-
public SnapshotDto setCreatedAt(Long createdAt) {
this.createdAt = createdAt;
return this;
diff --git a/sonar-core/src/main/java/org/sonar/core/metric/db/MetricDto.java b/sonar-core/src/main/java/org/sonar/core/metric/db/MetricDto.java
index 233e3616075..9e725c435bb 100644
--- a/sonar-core/src/main/java/org/sonar/core/metric/db/MetricDto.java
+++ b/sonar-core/src/main/java/org/sonar/core/metric/db/MetricDto.java
@@ -47,13 +47,13 @@ public class MetricDto {
private Double bestValue;
- private Boolean optimizedBestValue;
+ private boolean optimizedBestValue;
private String origin;
- private Boolean hidden;
+ private boolean hidden;
- private Boolean deleteHistoricalData;
+ private boolean deleteHistoricalData;
private boolean enabled;
@@ -162,15 +162,11 @@ public class MetricDto {
return this;
}
- /**
- * @return null for manual metrics
- */
- @CheckForNull
- public Boolean isOptimizedBestValue() {
+ public boolean isOptimizedBestValue() {
return optimizedBestValue;
}
- public MetricDto setOptimizedBestValue(@Nullable Boolean optimizedBestValue) {
+ public MetricDto setOptimizedBestValue(boolean optimizedBestValue) {
this.optimizedBestValue = optimizedBestValue;
return this;
}
@@ -184,28 +180,20 @@ public class MetricDto {
return this;
}
- /**
- * @return null for manual metrics
- */
- @CheckForNull
- public Boolean isHidden() {
+ public boolean isHidden() {
return hidden;
}
- public MetricDto setHidden(@Nullable Boolean hidden) {
+ public MetricDto setHidden(boolean hidden) {
this.hidden = hidden;
return this;
}
- /**
- * @return null for manual metrics
- */
- @CheckForNull
- public Boolean isDeleteHistoricalData() {
+ public boolean isDeleteHistoricalData() {
return deleteHistoricalData;
}
- public MetricDto setDeleteHistoricalData(@Nullable Boolean deleteHistoricalData) {
+ public MetricDto setDeleteHistoricalData(boolean deleteHistoricalData) {
this.deleteHistoricalData = deleteHistoricalData;
return this;
}
diff --git a/sonar-core/src/main/java/org/sonar/core/notification/DefaultNotificationManager.java b/sonar-core/src/main/java/org/sonar/core/notification/DefaultNotificationManager.java
index 99dbf58c3e2..6857590edda 100644
--- a/sonar-core/src/main/java/org/sonar/core/notification/DefaultNotificationManager.java
+++ b/sonar-core/src/main/java/org/sonar/core/notification/DefaultNotificationManager.java
@@ -25,6 +25,11 @@ import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.SetMultimap;
+import java.io.IOException;
+import java.io.InvalidClassException;
+import java.util.Arrays;
+import java.util.List;
+import javax.annotation.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonar.api.batch.RequiresDB;
@@ -35,13 +40,6 @@ import org.sonar.core.notification.db.NotificationQueueDao;
import org.sonar.core.notification.db.NotificationQueueDto;
import org.sonar.core.properties.PropertiesDao;
-import javax.annotation.Nullable;
-
-import java.io.IOException;
-import java.io.InvalidClassException;
-import java.util.Arrays;
-import java.util.List;
-
/**
* @since 2.10
*/
@@ -175,7 +173,7 @@ public class DefaultNotificationManager implements NotificationManager {
return Arrays.asList(notificationChannels);
}
- private void addUsersToRecipientListForChannel(List<String> users, SetMultimap<String, NotificationChannel> recipients, NotificationChannel channel) {
+ private static void addUsersToRecipientListForChannel(List<String> users, SetMultimap<String, NotificationChannel> recipients, NotificationChannel channel) {
for (String username : users) {
recipients.put(username, channel);
}
diff --git a/sonar-core/src/main/java/org/sonar/core/permission/PermissionQuery.java b/sonar-core/src/main/java/org/sonar/core/permission/PermissionQuery.java
index 003469b1550..3f651d3f528 100644
--- a/sonar-core/src/main/java/org/sonar/core/permission/PermissionQuery.java
+++ b/sonar-core/src/main/java/org/sonar/core/permission/PermissionQuery.java
@@ -22,12 +22,10 @@ package org.sonar.core.permission;
import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableSet;
-import org.apache.commons.lang.StringUtils;
-
+import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
-
-import java.util.Set;
+import org.apache.commons.lang.StringUtils;
/**
* Query used to get users and groups from a permission
@@ -70,7 +68,7 @@ public class PermissionQuery {
this.pageIndex = builder.pageIndex;
}
- private String searchToSql(@Nullable String s) {
+ private static String searchToSql(@Nullable String s) {
String sql = null;
if (s != null) {
sql = StringUtils.replace(StringUtils.upperCase(s), "%", "/%");
diff --git a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
index 9cf108aa1ae..a07de30f906 100644
--- a/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
+++ b/sonar-core/src/main/java/org/sonar/core/persistence/DatabaseVersion.java
@@ -35,7 +35,7 @@ import java.util.List;
@ServerSide
public class DatabaseVersion {
- public static final int LAST_VERSION = 915;
+ public static final int LAST_VERSION = 916;
/**
* List of all the tables.n
diff --git a/sonar-core/src/main/java/org/sonar/core/resource/ResourceKeyUpdaterDao.java b/sonar-core/src/main/java/org/sonar/core/resource/ResourceKeyUpdaterDao.java
index 37d41bac024..34aa6008dee 100644
--- a/sonar-core/src/main/java/org/sonar/core/resource/ResourceKeyUpdaterDao.java
+++ b/sonar-core/src/main/java/org/sonar/core/resource/ResourceKeyUpdaterDao.java
@@ -22,15 +22,14 @@ package org.sonar.core.resource;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
-import org.apache.commons.lang.StringUtils;
-import org.apache.ibatis.session.SqlSession;
-import org.sonar.core.persistence.DbSession;
-import org.sonar.core.persistence.MyBatis;
-
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
+import org.apache.commons.lang.StringUtils;
+import org.apache.ibatis.session.SqlSession;
+import org.sonar.core.persistence.DbSession;
+import org.sonar.core.persistence.MyBatis;
/**
* Class used to rename the key of a project and its resources.
@@ -117,11 +116,11 @@ public class ResourceKeyUpdaterDao {
}
}
- private String computeNewKey(ResourceDto resource, String stringToReplace, String replacementString) {
+ private static String computeNewKey(ResourceDto resource, String stringToReplace, String replacementString) {
return resource.getKey().replaceAll(stringToReplace, replacementString);
}
- private void runBatchUpdateForAllResources(Collection<ResourceDto> resources, String oldKey, String newKey, ResourceKeyUpdaterMapper mapper) {
+ private static void runBatchUpdateForAllResources(Collection<ResourceDto> resources, String oldKey, String newKey, ResourceKeyUpdaterMapper mapper) {
for (ResourceDto resource : resources) {
String resourceKey = resource.getKey();
resource.setKey(newKey + resourceKey.substring(oldKey.length(), resourceKey.length()));
diff --git a/sonar-core/src/main/java/org/sonar/core/timemachine/Periods.java b/sonar-core/src/main/java/org/sonar/core/timemachine/Periods.java
index cc7bb97cf8b..09214a071de 100644
--- a/sonar-core/src/main/java/org/sonar/core/timemachine/Periods.java
+++ b/sonar-core/src/main/java/org/sonar/core/timemachine/Periods.java
@@ -19,22 +19,20 @@
*/
package org.sonar.core.timemachine;
+import java.text.ParseException;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.Locale;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
import org.apache.commons.lang.StringUtils;
-import org.sonar.api.batch.BatchSide;
import org.sonar.api.CoreProperties;
-import org.sonar.api.server.ServerSide;
+import org.sonar.api.batch.BatchSide;
import org.sonar.api.batch.RequiresDB;
import org.sonar.api.config.Settings;
import org.sonar.api.database.model.Snapshot;
import org.sonar.api.i18n.I18n;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
-import java.text.ParseException;
-import java.text.SimpleDateFormat;
-import java.util.Date;
-import java.util.Locale;
+import org.sonar.api.server.ServerSide;
import static org.sonar.api.utils.DateUtils.longToDate;
@@ -133,7 +131,7 @@ public class Periods {
}
@CheckForNull
- private String convertDate(Date date) {
+ private static String convertDate(Date date) {
if (date != null) {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy MMM dd");
return dateFormat.format(date);
@@ -141,7 +139,7 @@ public class Periods {
return null;
}
- private Locale getLocale() {
+ private static Locale getLocale() {
return Locale.ENGLISH;
}
@@ -168,7 +166,7 @@ public class Periods {
}
}
- private Integer findByDays(String property) {
+ private static Integer findByDays(String property) {
try {
return Integer.parseInt(property);
} catch (NumberFormatException e) {
@@ -176,7 +174,7 @@ public class Periods {
}
}
- private Date findByDate(String property) {
+ private static Date findByDate(String property) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd");
try {
return format.parse(property);
diff --git a/sonar-core/src/main/java/org/sonar/core/user/GroupMembershipQuery.java b/sonar-core/src/main/java/org/sonar/core/user/GroupMembershipQuery.java
index 1fae7519f9d..75f1fdb44b0 100644
--- a/sonar-core/src/main/java/org/sonar/core/user/GroupMembershipQuery.java
+++ b/sonar-core/src/main/java/org/sonar/core/user/GroupMembershipQuery.java
@@ -64,7 +64,7 @@ public class GroupMembershipQuery {
this.pageIndex = builder.pageIndex;
}
- private String groupSearchToSql(@Nullable String s) {
+ private static String groupSearchToSql(@Nullable String s) {
String sql = null;
if (s != null) {
sql = StringUtils.replace(StringUtils.upperCase(s), "%", "/%");
diff --git a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
index a985006dde7..714266f33da 100644
--- a/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
+++ b/sonar-core/src/main/resources/org/sonar/core/persistence/rows-h2.sql
@@ -339,6 +339,7 @@ INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('912');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('913');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('914');
INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('915');
+INSERT INTO SCHEMA_MIGRATIONS(VERSION) VALUES ('916');
INSERT INTO USERS(ID, LOGIN, NAME, EMAIL, CRYPTED_PASSWORD, SALT, CREATED_AT, UPDATED_AT, REMEMBER_TOKEN, REMEMBER_TOKEN_EXPIRES_AT) VALUES (1, 'admin', 'Administrator', '', 'a373a0e667abb2604c1fd571eb4ad47fe8cc0878', '48bc4b0d93179b5103fd3885ea9119498e9d161b', '1418215735482', '1418215735482', null, null);
ALTER TABLE USERS ALTER COLUMN ID RESTART WITH 2;
diff --git a/sonar-core/src/test/java/org/sonar/core/component/ModuleTest.java b/sonar-core/src/test/java/org/sonar/core/component/ModuleTest.java
new file mode 100644
index 00000000000..5a2f061a7c8
--- /dev/null
+++ b/sonar-core/src/test/java/org/sonar/core/component/ModuleTest.java
@@ -0,0 +1,80 @@
+/*
+ * SonarQube, open source software quality management tool.
+ * Copyright (C) 2008-2014 SonarSource
+ * mailto:contact AT sonarsource DOT com
+ *
+ * SonarQube is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * SonarQube is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.core.component;
+
+import org.junit.Test;
+import org.sonar.core.platform.ComponentContainer;
+
+import static org.assertj.core.api.Assertions.assertThat;
+
+public class ModuleTest {
+ ComponentContainer container = new ComponentContainer();
+ int initialSize = sizeOf(container);
+
+ @Test(expected = NullPointerException.class)
+ public void configure_throws_NPE_if_container_is_empty() {
+ new Module() {
+ @Override
+ protected void configureModule() {
+ // empty
+ }
+ }.configure(null);
+ }
+
+ @Test
+ public void module_with_empty_configureModule_method_adds_no_component() {
+ new Module() {
+ @Override
+ protected void configureModule() {
+ // empty
+ }
+ }.configure(container);
+
+ assertThat(sizeOf(container)).isSameAs(initialSize);
+ }
+
+ @Test
+ public void add_method_supports_null_and_adds_nothing_to_container() {
+ new Module() {
+ @Override
+ protected void configureModule() {
+ add(null);
+ }
+ }.configure(container);
+
+ assertThat(sizeOf(container)).isEqualTo(initialSize);
+ }
+
+ @Test
+ public void add_method_filters_out_null_inside_vararg_parameter() {
+ new Module() {
+ @Override
+ protected void configureModule() {
+ add(new Object(), null, "");
+ }
+ }.configure(container);
+
+ assertThat(sizeOf(container)).isEqualTo(initialSize + 2);
+ }
+
+ private static int sizeOf(ComponentContainer container) {
+ return container.getPicoContainer().getComponentAdapters().size();
+ }
+}
diff --git a/sonar-core/src/test/java/org/sonar/core/component/SnapshotDtoTest.java b/sonar-core/src/test/java/org/sonar/core/component/SnapshotDtoTest.java
index 5e84ecbbd65..26a4aad9825 100644
--- a/sonar-core/src/test/java/org/sonar/core/component/SnapshotDtoTest.java
+++ b/sonar-core/src/test/java/org/sonar/core/component/SnapshotDtoTest.java
@@ -59,7 +59,6 @@ public class SnapshotDtoTest {
.setPeriodDate(5, parseDate("2014-06-05").getTime());
assertThat(snapshotDto.getId()).isEqualTo(10L);
- assertThat(snapshotDto.getKey()).isEqualTo(10L);
assertThat(snapshotDto.getParentId()).isEqualTo(2L);
assertThat(snapshotDto.getRootId()).isEqualTo(3L);
assertThat(snapshotDto.getRootProjectId()).isEqualTo(20L);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java
index faa300d2590..b8b6eaefc2a 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/issue/internal/FieldDiffs.java
@@ -22,13 +22,11 @@ package org.sonar.api.issue.internal;
import com.google.common.base.Splitter;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
-
-import javax.annotation.CheckForNull;
-import javax.annotation.Nullable;
-
import java.io.Serializable;
import java.util.Date;
import java.util.Map;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nullable;
/**
* PLUGINS MUST NOT USE THIS CLASS, EXCEPT FOR UNIT TESTING.
@@ -168,7 +166,7 @@ public class FieldDiffs implements Serializable {
}
@CheckForNull
- private Long toLong(Serializable value) {
+ private static Long toLong(@Nullable Serializable value) {
if (value != null && !"".equals(value)) {
try {
return Long.valueOf((String) value);
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java b/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java
index 64283bfdce1..976508710d6 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/measures/AverageFormula.java
@@ -20,9 +20,8 @@
package org.sonar.api.measures;
-import org.sonar.api.resources.ResourceUtils;
-
import java.util.List;
+import org.sonar.api.resources.ResourceUtils;
import static com.google.common.collect.Lists.newArrayList;
@@ -130,7 +129,7 @@ public class AverageFormula implements Formula {
return result;
}
- private boolean shouldDecorateResource(FormulaData data, FormulaContext context) {
+ private static boolean shouldDecorateResource(FormulaData data, FormulaContext context) {
return !MeasureUtils.hasValue(data.getMeasure(context.getTargetMetric()));
}
}
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Rule.java b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Rule.java
index 0014f8df527..d0489dd9a65 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/rules/Rule.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/rules/Rule.java
@@ -22,16 +22,10 @@ package org.sonar.api.rules;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableSet;
-import org.apache.commons.lang.StringUtils;
-import org.apache.commons.lang.builder.EqualsBuilder;
-import org.apache.commons.lang.builder.HashCodeBuilder;
-import org.apache.commons.lang.builder.ToStringBuilder;
-import org.apache.commons.lang.builder.ToStringStyle;
-import org.sonar.api.database.DatabaseProperties;
-import org.sonar.api.rule.RuleKey;
-import org.sonar.api.utils.SonarException;
-import org.sonar.check.Cardinality;
-
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.Set;
import javax.annotation.CheckForNull;
import javax.annotation.Nullable;
import javax.persistence.Column;
@@ -48,11 +42,15 @@ import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-import java.util.Set;
+import org.apache.commons.lang.StringUtils;
+import org.apache.commons.lang.builder.EqualsBuilder;
+import org.apache.commons.lang.builder.HashCodeBuilder;
+import org.apache.commons.lang.builder.ToStringBuilder;
+import org.apache.commons.lang.builder.ToStringStyle;
+import org.sonar.api.database.DatabaseProperties;
+import org.sonar.api.rule.RuleKey;
+import org.sonar.api.utils.SonarException;
+import org.sonar.check.Cardinality;
@Entity
@Table(name = "rules")
@@ -560,7 +558,7 @@ public class Rule {
}
@CheckForNull
- private String removeNewLineCharacters(@Nullable String text) {
+ private static String removeNewLineCharacters(@Nullable String text) {
String removedCRLF = StringUtils.remove(text, "\n");
removedCRLF = StringUtils.remove(removedCRLF, "\r");
removedCRLF = StringUtils.remove(removedCRLF, "\n\r");
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleParamType.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleParamType.java
index cc8c3b7b897..1d2abe1cdf3 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleParamType.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/rule/RuleParamType.java
@@ -19,12 +19,11 @@
*/
package org.sonar.api.server.rule;
+import java.util.List;
import org.apache.commons.lang.StringEscapeUtils;
import org.apache.commons.lang.StringUtils;
import org.sonar.api.PropertyType;
-import java.util.List;
-
import static com.google.common.collect.Lists.newArrayList;
/**
@@ -75,7 +74,7 @@ public final class RuleParamType {
this.multiple = multiple;
}
- private String valuesToCsv(String... values) {
+ private static String valuesToCsv(String... values) {
StringBuilder sb = new StringBuilder();
for (String value : values) {
sb.append(StringEscapeUtils.escapeCsv(value));
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
index 49c9c0adf2c..418caff6e84 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/server/ws/WebService.java
@@ -19,7 +19,9 @@
*/
package org.sonar.api.server.ws;
+import com.google.common.base.Function;
import com.google.common.base.Joiner;
+import com.google.common.base.Preconditions;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
@@ -33,6 +35,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;
import org.apache.commons.io.FilenameUtils;
@@ -385,6 +388,18 @@ public interface WebService extends Definable<WebService.Context> {
.setDefaultValue(defaultAscending);
return this;
}
+
+ /**
+ * Add 'selected=(selected|deselected|all)' for select-list oriented WS.
+ */
+ public NewAction addSelectionModeParam() {
+ createParam(Param.SELECTED)
+ .setDescription("Depending on the value, show only selected items (selected=selected), deselected items (selected=deselected), " +
+ "or all items with their selection status (selected=all).")
+ .setDefaultValue(SelectionMode.SELECTED.value())
+ .setPossibleValues(SelectionMode.possibleValues());
+ return this;
+ }
}
@Immutable
@@ -592,6 +607,36 @@ public interface WebService extends Definable<WebService.Context> {
}
}
+ enum SelectionMode {
+ SELECTED("selected"), DESELECTED("deselected"), ALL("all");
+
+ private final String paramValue;
+
+ private static final Map<String, SelectionMode> BY_VALUE = Maps.uniqueIndex(Arrays.asList(values()), new Function<SelectionMode, String>() {
+ @Override
+ public String apply(@Nonnull SelectionMode input) {
+ return input.paramValue;
+ }
+ });
+
+ private SelectionMode(String paramValue) {
+ this.paramValue = paramValue;
+ }
+
+ public String value() {
+ return paramValue;
+ }
+
+ public static SelectionMode fromParam(String paramValue) {
+ Preconditions.checkArgument(BY_VALUE.containsKey(paramValue));
+ return BY_VALUE.get(paramValue);
+ }
+
+ public static Collection<String> possibleValues() {
+ return BY_VALUE.keySet();
+ }
+ }
+
@Immutable
class Param {
public static final String TEXT_QUERY = "q";
@@ -601,6 +646,7 @@ public interface WebService extends Definable<WebService.Context> {
public static final String SORT = "s";
public static final String ASCENDING = "asc";
public static final String FACETS = "facets";
+ public static final String SELECTED = "selected";
private final String key, deprecatedKey, description, exampleValue, defaultValue;
private final boolean required;
diff --git a/sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java
index 6f0eccafb45..4f88279c6d5 100644
--- a/sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java
+++ b/sonar-plugin-api/src/main/java/org/sonar/api/utils/Durations.java
@@ -20,16 +20,14 @@
package org.sonar.api.utils;
+import java.util.Locale;
+import javax.annotation.CheckForNull;
import org.sonar.api.CoreProperties;
import org.sonar.api.batch.BatchSide;
import org.sonar.api.config.Settings;
import org.sonar.api.i18n.I18n;
import org.sonar.api.server.ServerSide;
-import javax.annotation.CheckForNull;
-
-import java.util.Locale;
-
/**
* Used through ruby code <pre>Internal.durations</pre>
*
@@ -133,15 +131,15 @@ public class Durations {
return i18n.message(locale, key, null, parameter);
}
- private boolean displayHours(int days, int hours) {
+ private static boolean displayHours(int days, int hours) {
return hours > 0 && days < 10;
}
- private boolean displayMinutes(int days, int hours, int minutes) {
+ private static boolean displayMinutes(int days, int hours, int minutes) {
return minutes > 0 && hours < 10 && days == 0;
}
- private void addSpaceIfNeeded(StringBuilder message) {
+ private static void addSpaceIfNeeded(StringBuilder message) {
if (message.length() > 0) {
message.append(" ");
}