diff options
author | Stas Vilchik <vilchiks@gmail.com> | 2014-12-24 17:18:45 +0100 |
---|---|---|
committer | Stas Vilchik <vilchiks@gmail.com> | 2014-12-24 17:18:45 +0100 |
commit | c158c1b03e2fbc205a310e2fc8b20c35ec4ccbad (patch) | |
tree | 3e1c46a6870ee424d506f21722580f08c28e020c | |
parent | 008a6d3ea04cacebbc2e7b5efdfddcfa024eb48e (diff) | |
download | sonarqube-c158c1b03e2fbc205a310e2fc8b20c35ec4ccbad.tar.gz sonarqube-c158c1b03e2fbc205a310e2fc8b20c35ec4ccbad.zip |
SONAR-5820 Provide a permalink on each rule description
13 files changed, 569 insertions, 3 deletions
diff --git a/server/sonar-web/Gruntfile.coffee b/server/sonar-web/Gruntfile.coffee index 736f83885b8..4e00555ddfa 100644 --- a/server/sonar-web/Gruntfile.coffee +++ b/server/sonar-web/Gruntfile.coffee @@ -174,6 +174,10 @@ module.exports = (grunt) -> name: 'coding-rules/app' out: '<%= pkg.assets %>build/js/coding-rules/app.js' + codingRulesShow: options: + name: 'coding-rules/app' + out: '<%= pkg.assets %>build/js/coding-rules/show-app.js' + codingRulesOld: options: name: 'coding-rules-old/app' out: '<%= pkg.assets %>build/js/coding-rules-old/app.js' diff --git a/server/sonar-web/src/main/coffee/issue/views/rule-overlay.coffee b/server/sonar-web/src/main/coffee/issue/views/rule-overlay.coffee index 78415e338e0..54d13bd8f0a 100644 --- a/server/sonar-web/src/main/coffee/issue/views/rule-overlay.coffee +++ b/server/sonar-web/src/main/coffee/issue/views/rule-overlay.coffee @@ -12,5 +12,5 @@ define [ serializeData: -> _.extend super, - permalink: "#{baseUrl}/coding_rules#rule_key=#{@model.get('key')}" + permalink: "#{baseUrl}/coding_rules/show?key=#{encodeURIComponent @model.get('key')}" allTags: _.union @model.get('sysTags'), @model.get('tags') diff --git a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-meta.hbs b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-meta.hbs index 44cd94a7adf..383258b9bbb 100644 --- a/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-meta.hbs +++ b/server/sonar-web/src/main/hbs/coding-rules/rule/coding-rules-rule-meta.hbs @@ -1,6 +1,6 @@ <h3 class="coding-rules-detail-header"> {{name}} - <a class="coding-rules-detail-permalink icon-link" target="_blank" href="#rule_key={{key}}"></a> + <a class="coding-rules-detail-permalink icon-link" target="_blank" href="{{permalink}}"></a> </h3> <span class="subtitle">{{key}}</span> diff --git a/server/sonar-web/src/main/js/coding-rules/rule-details-view.js b/server/sonar-web/src/main/js/coding-rules/rule-details-view.js index 2e41d7663fa..051413e679f 100644 --- a/server/sonar-web/src/main/js/coding-rules/rule-details-view.js +++ b/server/sonar-web/src/main/js/coding-rules/rule-details-view.js @@ -9,6 +9,7 @@ define([ ], function (Backbone, Marionette, Templates, MetaView, DescView, ParamView, ProfilesView) { return Marionette.Layout.extend({ + className: 'coding-rule-details', template: Templates['coding-rules-rule-details'], regions: { diff --git a/server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js b/server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js index 6f3c3c36700..e01fa1d2942 100644 --- a/server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js +++ b/server/sonar-web/src/main/js/coding-rules/rule/rule-meta-view.js @@ -78,7 +78,8 @@ define([ return _.extend(Marionette.ItemView.prototype.serializeData.apply(this, arguments), { canWrite: this.options.app.canWrite, subCharacteristic: this.options.app.getSubCharacteristicName(this.model.get('debtSubChar')), - allTags: _.union(this.model.get('sysTags'), this.model.get('tags')) + allTags: _.union(this.model.get('sysTags'), this.model.get('tags')), + permalink: baseUrl + '/coding_rules/show?key=' + encodeURIComponent(this.model.id) }); } }); diff --git a/server/sonar-web/src/main/js/coding-rules/show-app.js b/server/sonar-web/src/main/js/coding-rules/show-app.js new file mode 100644 index 00000000000..ee68beb0df4 --- /dev/null +++ b/server/sonar-web/src/main/js/coding-rules/show-app.js @@ -0,0 +1,94 @@ +requirejs.config({ + baseUrl: baseUrl + '/js', + + paths: { + 'backbone': 'third-party/backbone', + 'backbone.marionette': 'third-party/backbone.marionette', + 'handlebars': 'third-party/handlebars' + }, + + shim: { + 'backbone.marionette': { + deps: ['backbone'], + exports: 'Marionette' + }, + 'backbone': { + exports: 'Backbone' + }, + 'handlebars': { + exports: 'Handlebars' + } + } +}); + + +requirejs([ + 'backbone', + 'backbone.marionette', + + 'coding-rules/models/rule', + 'coding-rules/rule-details-view', + + 'common/handlebars-extensions' +], + function (Backbone, + Marionette, + Rule, + RuleDetailsView) { + + var $ = jQuery, + App = new Marionette.Application(), + p = window.process.addBackgroundProcess(); + + App.addInitializer(function () { + var url = baseUrl + '/api/rules/show', + key = decodeURIComponent(window.location.search.substr(5)), + options = { + key: key, + actives: true + }; + $.get(url, options).done(function (data) { + this.ruleDetailsView = new RuleDetailsView({ + app: App, + model: new Rule(data.rule), + actives: data.actives + }); + this.ruleDetailsView.render().$el.appendTo($('.page')); + window.process.finishBackgroundProcess(p); + }).fail(function () { + window.process.failBackgroundProcess(p); + }); + }); + + App.manualRepository = function () { + return { + key: 'manual', + name: t('coding_rules.manual_rules'), + language: 'none' + }; + }; + + App.getSubCharacteristicName = function (name) { + return (App.characteristics[name] || '').replace(': ', ' > '); + }; + + var appXHR = $.get(baseUrl + '/api/rules/app').done(function(r) { + App.canWrite = r.canWrite; + App.qualityProfiles = _.sortBy(r.qualityprofiles, ['name', 'lang']); + App.languages = _.extend(r.languages, { + none: 'None' + }); + _.map(App.qualityProfiles, function(profile) { + profile.language = App.languages[profile.lang]; + }); + App.repositories = r.repositories; + App.repositories.push(App.manualRepository()); + App.statuses = r.statuses; + App.characteristics = r.characteristics; + }); + + $.when(window.requestMessages(), appXHR).done(function () { + App.start(); + }); + + }); diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/app.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/app.json new file mode 100644 index 00000000000..4f3319c8707 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/app.json @@ -0,0 +1,168 @@ +{ + "canWrite": false, + "qualityprofiles": [ + { + "key": "java-default-with-mojo-conventions-49307", + "name": "Default - Maven Conventions", + "lang": "java", + "parentKey": "java-top-profile-without-formatting-conventions-50037" + }, + { + "key": "java-default-with-sonarsource-conventions-27339", + "name": "Default - SonarSource conventions", + "lang": "java", + "parentKey": "java-top-profile-without-formatting-conventions-50037" + }, + { + "key": "java-top-profile-without-formatting-conventions-50037", + "name": "Default - Top", + "lang": "java" + }, + { + "key": "java-findbugs-14954", + "name": "FindBugs", + "lang": "java" + }, + { + "key": "java-for-sq-java-plugin-only-92289", + "name": "For SQ Java Plugin Only", + "lang": "java", + "parentKey": "java-default-with-sonarsource-conventions-27339" + }, + { + "key": "java-for-sq-only-95381", + "name": "For SQ Only", + "lang": "java", + "parentKey": "java-default-with-sonarsource-conventions-27339" + }, + { + "key": "php-psr-2-06315", + "name": "PSR-2", + "lang": "php" + }, + { + "key": "java-sonar-way-80423", + "name": "Sonar way", + "lang": "java" + }, + { + "key": "js-sonar-way", + "name": "Sonar way", + "lang": "js" + }, + { + "key": "php-sonar-way-05548", + "name": "Sonar way", + "lang": "php" + }, + { + "key": "py-sonar-way-80265", + "name": "Sonar way", + "lang": "py" + }, + { + "key": "java-without-findbugs", + "name": "Without Findbugs", + "lang": "java" + } + ], + "languages": { + "py": "Python", + "js": "JavaScript", + "php": "PHP", + "java": "Java" + }, + "repositories": [ + { + "key": "common-java", + "name": "Common SonarQube", + "language": "java" + }, + { + "key": "common-js", + "name": "Common SonarQube", + "language": "js" + }, + { + "key": "common-php", + "name": "Common SonarQube", + "language": "php" + }, + { + "key": "common-py", + "name": "Common SonarQube", + "language": "py" + }, + { + "key": "Pylint", + "name": "Pylint", + "language": "py" + }, + { + "key": "javascript", + "name": "SonarQube", + "language": "js" + }, + { + "key": "php", + "name": "SonarQube", + "language": "php" + }, + { + "key": "python", + "name": "SonarQube", + "language": "py" + }, + { + "key": "squid", + "name": "SonarQube", + "language": "java" + } + ], + "statuses": { + "BETA": "Beta", + "DEPRECATED": "Deprecated", + "READY": "Ready" + }, + "characteristics": { + "UNDERSTANDABILITY": "Maintainability: Understandability", + "MAINTAINABILITY": "Maintainability", + "TIME_ZONE_RELATED_PORTABILITY": "Portability: Time zone related portability", + "READABILITY": "Maintainability: Readability", + "SECURITY_FEATURES": "Security: Security features", + "ARCHITECTURE_RELIABILITY": "Reliability: Architecture related reliability", + "OS_RELATED_PORTABILITY": "Portability: OS related portability", + "EXCEPTION_HANDLING": "Reliability: Exception handling", + "LOGIC_CHANGEABILITY": "Changeability: Logic related changeability", + "SOFTWARE_RELATED_PORTABILITY": "Portability: Software related portability", + "INPUT_VALIDATION_AND_REPRESENTATION": "Security: Input validation and representation", + "LANGUAGE_RELATED_PORTABILITY": "Portability: Language related portability", + "ERRORS": "Security: Errors", + "SECURITY": "Security", + "RELIABILITY": "Reliability", + "PORTABILITY": "Portability", + "HARDWARE_RELATED_PORTABILITY": "Portability: Hardware related portability", + "SYNCHRONIZATION_RELIABILITY": "Reliability: Synchronization related reliability", + "TRANSPORTABILITY": "Reusability: Transportability", + "COMPILER_RELATED_PORTABILITY": "Portability: Compiler related portability", + "RESOURCE_RELIABILITY": "Reliability: Resource", + "CPU_EFFICIENCY": "Efficiency: Processor use", + "EFFICIENCY": "Efficiency", + "CHANGEABILITY": "Changeability", + "DATA_CHANGEABILITY": "Changeability: Data related changeability", + "API_ABUSE": "Security: API abuse", + "ARCHITECTURE_CHANGEABILITY": "Changeability: Architecture related changeability", + "UNIT_TESTS": "Reliability: Unit tests", + "INSTRUCTION_RELIABILITY": "Reliability: Instruction related reliability", + "REUSABILITY": "Reusability", + "MODULARITY": "Reusability: Modularity", + "UNIT_TESTABILITY": "Testability: Unit level testability", + "TESTABILITY": "Testability", + "INTEGRATION_TESTABILITY": "Testability: Integration level testability", + "NETWORK_USE": "Efficiency: Network use", + "MEMORY_EFFICIENCY": "Efficiency: Memory use", + "DATA_RELIABILITY": "Reliability: Data related reliability", + "FAULT_TOLERANCE": "Reliability: Fault tolerance", + "LOGIC_RELIABILITY": "Reliability: Logic related reliability" + } +} diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/search.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/search.json new file mode 100644 index 00000000000..b5a6bc269b9 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/search.json @@ -0,0 +1,171 @@ +{ + "total": 10, + "p": 1, + "ps": 200, + "rules": [ + { + "key": "squid:S1181", + "name": "Throwable and Error classes should not be caught", + "lang": "java", + "langName": "Java", + "sysTags": [ + "error-handling" + ], + "tags": [] + }, + { + "key": "squid:S1849", + "name": "\"Iterator.hasNext()\" should not call \"Iterator.next()\"", + "lang": "java", + "langName": "Java", + "sysTags": [ + "bug" + ], + "tags": [] + }, + { + "key": "squid:S1844", + "name": "\"Object.wait(...)\" should never be called on objects that implement \"java.util.concurrent.locks.Condition\"", + "lang": "java", + "langName": "Java", + "sysTags": [ + "bug", + "pitfall" + ], + "tags": [] + }, + { + "key": "squid:S2258", + "name": "\"javax.crypto.NullCipher\" should not be used for anything other than testing", + "lang": "java", + "langName": "Java", + "sysTags": [ + "cwe", + "owasp-top10", + "security" + ], + "tags": [] + }, + { + "key": "squid:S2251", + "name": "A \"for\" loop update clause should move the counter in the right direction", + "lang": "java", + "langName": "Java", + "sysTags": [ + "bug" + ], + "tags": [] + }, + { + "key": "squid:ObjectFinalizeOverridenCallsSuperFinalizeCheck", + "name": "super.finalize() should be called at the end of Object.finalize() implementations", + "lang": "java", + "langName": "Java", + "sysTags": [ + "bug" + ], + "tags": [] + }, + { + "key": "squid:S1143", + "name": "Return statements should not occur in finally blocks", + "lang": "java", + "langName": "Java", + "sysTags": [ + "bug" + ], + "tags": [] + }, + { + "key": "squid:S1206", + "name": "\"equals(Object obj)\" and \"hashCode()\" should be overridden in pairs", + "lang": "java", + "langName": "Java", + "sysTags": [ + "bug" + ], + "tags": [] + }, + { + "key": "squid:S1451", + "name": "Copyright and license headers should be defined in all source files", + "lang": "java", + "langName": "Java", + "sysTags": [ + "convention" + ], + "tags": [] + }, + { + "key": "squid:S1697", + "name": "Short-circuit logic should be used to prevent null pointer dereferences in conditionals", + "lang": "java", + "langName": "Java", + "sysTags": [ + "bug" + ], + "tags": [] + } + ], + "facets": [ + { + "property": "tags", + "values": [ + { + "val": "bug", + "count": 7 + }, + { + "val": "convention", + "count": 1 + }, + { + "val": "cwe", + "count": 1 + }, + { + "val": "error-handling", + "count": 1 + }, + { + "val": "owasp-top10", + "count": 1 + }, + { + "val": "pitfall", + "count": 1 + }, + { + "val": "security", + "count": 1 + } + ] + }, + { + "property": "languages", + "values": [ + { + "val": "java", + "count": 10 + }, + { + "val": "js", + "count": 6 + }, + { + "val": "php", + "count": 2 + } + ] + }, + { + "property": "repositories", + "values": [ + { + "val": "squid", + "count": 10 + } + ] + } + ] +} diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/show.json b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/show.json new file mode 100644 index 00000000000..274b587bfb2 --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-permalink/show.json @@ -0,0 +1,76 @@ +{ + "rule": { + "key": "squid:S1181", + "repo": "squid", + "name": "Throwable and Error classes should not be caught", + "createdAt": "2013-08-09T14:40:54+0200", + "severity": "BLOCKER", + "status": "READY", + "internalKey": "S1181", + "isTemplate": false, + "tags": [], + "sysTags": [ + "error-handling" + ], + "lang": "java", + "langName": "Java", + "htmlDesc": "<p>\n<code>Throwable</code> is the superclass of all errors and exceptions in Java.\n<code>Error</code> is the superclass of all errors which are not meant to be caught by applications.\n</p>\n\n<p>\nCatching either <code>Throwable</code> or <code>Error</code> will also catch <code>OutOfMemoryError</code> or <code>InternalError</code> from which an application should not attempt to recover.\n</p>\n\n<p>Only <code>Exception</code> and its subclasses should be caught.</p>\n\n<h2>Noncompliant Code Example</h2>\n\n<pre>\ntry { /* ... */ } catch (Throwable t) { /* ... */ }\ntry { /* ... */ } catch (Error e) { /* ... */ } \n</pre>\n\n<h2>Compliant Solution</h2>\n\n<pre>\ntry { /* ... */ } catch (Exception e) { /* ... */ } \ntry { /* ... */ } catch (RuntimeException e) { /* ... */ } \ntry { /* ... */ } catch (MyException e) { /* ... */ } \n</pre>", + "defaultDebtChar": "RELIABILITY", + "defaultDebtSubChar": "EXCEPTION_HANDLING", + "debtChar": "RELIABILITY", + "debtSubChar": "EXCEPTION_HANDLING", + "debtCharName": "Reliability", + "debtSubCharName": "Exception handling", + "defaultDebtRemFnType": "CONSTANT_ISSUE", + "defaultDebtRemFnOffset": "20min", + "debtOverloaded": true, + "debtRemFnType": "LINEAR", + "debtRemFnCoeff": "20min", + "params": [ + { + "key": "max", + "htmlDesc": "Maximum authorized number of parameters", + "type": "INTEGER", + "defaultValue": "7" + } + ] + }, + "actives": [ + { + "qProfile": "java-top-profile-without-formatting-conventions-50037", + "inherit": "NONE", + "severity": "BLOCKER", + "params": [] + }, + { + "qProfile": "java-default-with-sonarsource-conventions-27339", + "inherit": "INHERITED", + "severity": "BLOCKER", + "params": [] + }, + { + "qProfile": "java-for-sq-java-plugin-only-92289", + "inherit": "INHERITED", + "severity": "BLOCKER", + "params": [] + }, + { + "qProfile": "java-for-sq-only-95381", + "inherit": "INHERITED", + "severity": "BLOCKER", + "params": [] + }, + { + "qProfile": "java-default-with-mojo-conventions-49307", + "inherit": "INHERITED", + "severity": "BLOCKER", + "params": [] + }, + { + "qProfile": "java-sonar-way-80423", + "inherit": "NONE", + "severity": "BLOCKER", + "params": [] + } + ] +} diff --git a/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-should-have-permalink.js b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-should-have-permalink.js new file mode 100644 index 00000000000..75898fd15fe --- /dev/null +++ b/server/sonar-web/src/main/js/tests/e2e/tests/coding-rules-page-rule-should-have-permalink.js @@ -0,0 +1,36 @@ +/* global casper:false */ + +var lib = require('../lib'); + +lib.initMessages(); +lib.changeWorkingDirectory('coding-rules-page-rule-permalink'); + + +casper.test.begin('coding-rules-page-rule-permalink', 1, function (test) { + casper + .start(lib.buildUrl('coding-rules'), function () { + lib.setDefaultViewport(); + + lib.mockRequest('/api/l10n/index', '{}'); + lib.mockRequestFromFile('/api/rules/app', 'app.json'); + lib.mockRequestFromFile('/api/rules/search', 'search.json'); + lib.mockRequestFromFile('/api/rules/show', 'show.json'); + }) + + .then(function () { + casper.waitForSelector('.coding-rule.selected'); + }) + + .then(function () { + casper.click('.coding-rule.selected .js-rule'); + casper.waitForSelector('.coding-rules-detail-header'); + }) + + .then(function () { + test.assertExists('a[href="/coding_rules/show?key=squid%3AS1181"]'); + }) + + .run(function () { + test.done(); + }); +}); diff --git a/server/sonar-web/src/main/less/components/rules.less b/server/sonar-web/src/main/less/components/rules.less index affe5c40766..41793326f44 100644 --- a/server/sonar-web/src/main/less/components/rules.less +++ b/server/sonar-web/src/main/less/components/rules.less @@ -57,3 +57,7 @@ content: ""; } } + +.coding-rule-details { + max-width: 1020px; +} diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb index cc4298b9383..04900e82a39 100644 --- a/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/controllers/coding_rules_controller.rb @@ -27,4 +27,9 @@ class CodingRulesController < ApplicationController end + # GET /coding_rules/show + def show + + end + end diff --git a/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/show.html.erb b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/show.html.erb new file mode 100644 index 00000000000..629a4a120d0 --- /dev/null +++ b/server/sonar-web/src/main/webapp/WEB-INF/app/views/coding_rules/show.html.erb @@ -0,0 +1,6 @@ +<% content_for :script do %> + <script data-main="<%= ApplicationController.root_context -%>/js/coding-rules/show-app" src="<%= ApplicationController.root_context -%>/js/require.js"></script> +<% end %> + + +<div class="page"></div> |