@@ -49,7 +49,7 @@ If you're starting from scratch: | |||
1. Do the [setup for your project](/#sonarcloud#/projects/create) (from the `+ > Analyze new project` top right menu) | |||
* ![](/images/exclamation.svg) Remember that your project must absolutely be created by selecting a GitHub repository - otherwise it won't work. | |||
1. Once the setup is done on SonarCloud, you end up on the project home page which shows a tutorial. Ignore it and simply add a `.sonarcloud.properties` file in the base directory of your default branch (or on a PR which targets this default branch). | |||
1. Once the setup is done on SonarCloud, you end up on the project home page which shows a tutorial. Ignore it and simply add a `.sonarcloud.properties` file in the base directory of your default branch or on a PR. | |||
1. After a while, the analysis results will be visible in SonarCloud (and your PR will be annotated with comments if you pushed the file on a PR) | |||
Here are the supported optional settings for the `.sonarcloud.properties` file: |
@@ -1,6 +1,11 @@ | |||
{ | |||
"extends": "sonarqube", | |||
"plugins": [ | |||
"react-hooks" | |||
], | |||
"rules": { | |||
"camelcase": "off" | |||
"camelcase": "off", | |||
"react-hooks/rules-of-hooks": "error", | |||
"react-hooks/exhaustive-deps": "warn" | |||
} | |||
} |
@@ -5,7 +5,6 @@ | |||
"repository": "SonarSource/sonarqube", | |||
"license": "LGPL-3.0", | |||
"dependencies": { | |||
"@types/dompurify": "^0.0.32", | |||
"classnames": "2.2.6", | |||
"clipboard": "2.0.1", | |||
"core-js": "3.0.0", | |||
@@ -17,7 +16,7 @@ | |||
"d3-shape": "1.2.2", | |||
"d3-zoom": "1.7.3", | |||
"date-fns": "1.29.0", | |||
"dompurify": "^1.0.11", | |||
"dompurify": "1.0.11", | |||
"formik": "1.2.0", | |||
"history": "3.3.0", | |||
"intl-relativeformat": "2.1.0", | |||
@@ -26,10 +25,10 @@ | |||
"lunr": "2.3.4", | |||
"mdast-util-toc": "2.1.0", | |||
"prop-types": "15.7.2", | |||
"react": "16.8.5", | |||
"react": "16.8.6", | |||
"react-countup": "4.1.1", | |||
"react-day-picker": "7.3.0", | |||
"react-dom": "16.8.5", | |||
"react-dom": "16.8.6", | |||
"react-draggable": "3.2.1", | |||
"react-helmet": "5.2.0", | |||
"react-intl": "2.8.0", | |||
@@ -66,13 +65,14 @@ | |||
"@types/d3-selection": "1.3.2", | |||
"@types/d3-shape": "1.2.4", | |||
"@types/d3-zoom": "1.7.2", | |||
"@types/enzyme": "3.9.1", | |||
"@types/jest": "24.0.11", | |||
"@types/dompurify": "0.0.32", | |||
"@types/enzyme": "3.9.3", | |||
"@types/jest": "24.0.15", | |||
"@types/keymaster": "1.6.28", | |||
"@types/lodash": "4.14.123", | |||
"@types/prop-types": "15.7.0", | |||
"@types/react": "16.8.8", | |||
"@types/react-dom": "16.8.3", | |||
"@types/react": "16.8.22", | |||
"@types/react-dom": "16.8.4", | |||
"@types/react-helmet": "5.0.8", | |||
"@types/react-intl": "2.3.17", | |||
"@types/react-modal": "3.8.1", | |||
@@ -85,7 +85,7 @@ | |||
"@typescript-eslint/parser": "1.5.0", | |||
"autoprefixer": "9.5.0", | |||
"babel-core": "7.0.0-bridge.0", | |||
"babel-jest": "24.5.0", | |||
"babel-jest": "24.8.0", | |||
"babel-loader": "8.0.5", | |||
"babel-plugin-dynamic-import-node": "2.2.0", | |||
"babel-plugin-lodash": "3.3.4", | |||
@@ -94,8 +94,8 @@ | |||
"copy-webpack-plugin": "5.0.1", | |||
"css-loader": "2.1.1", | |||
"cssnano": "4.1.10", | |||
"enzyme": "3.9.0", | |||
"enzyme-adapter-react-16": "1.10.0", | |||
"enzyme": "3.10.0", | |||
"enzyme-adapter-react-16": "1.14.0", | |||
"enzyme-to-json": "3.3.5", | |||
"escape-string-regexp": "1.0.5", | |||
"eslint": "5.15.3", | |||
@@ -104,12 +104,13 @@ | |||
"eslint-plugin-jsx-a11y": "6.2.1", | |||
"eslint-plugin-promise": "4.0.1", | |||
"eslint-plugin-react": "7.12.4", | |||
"eslint-plugin-react-hooks": "1.6.0", | |||
"eslint-plugin-sonarjs": "0.3.0", | |||
"expose-loader": "0.7.5", | |||
"glob": "7.1.3", | |||
"glob-promise": "3.4.0", | |||
"html-webpack-plugin": "3.2.0", | |||
"jest": "24.5.0", | |||
"jest": "24.8.0", | |||
"lint-staged": "7.3.0", | |||
"lodash-webpack-plugin": "0.11.5", | |||
"mini-css-extract-plugin": "0.6.0", | |||
@@ -120,7 +121,7 @@ | |||
"raw-loader": "2.0.0", | |||
"react-dev-utils": "5.0.1", | |||
"react-error-overlay": "1.0.7", | |||
"react-test-renderer": "16.8.5", | |||
"react-test-renderer": "16.8.6", | |||
"remark": "9.0.0", | |||
"remark-react": "4.0.3", | |||
"style-loader": "0.23.1", |
@@ -0,0 +1 @@ | |||
<svg width="90" height="90" xmlns="http://www.w3.org/2000/svg"><g stroke="#236A97" stroke-width="2" fill="none" fill-rule="evenodd"><path d="M32.087 83H12V12h66v71H57.913"/><path d="M57.79 78H72V18H18v60h14.21M12 12h66V1H12zM17 7h3M23 7h3M28 7h3M34 7h40"/><path d="M56.355 48.275c0 6.258-5.083 11.327-11.355 11.327s-11.355-5.069-11.355-11.327S38.728 36.948 45 36.948s11.355 5.069 11.355 11.327z"/><path d="M61.336 55.028a7.07 7.07 0 0 1-1.276 8.27 7.114 7.114 0 0 1-8.29 1.273A7.101 7.101 0 0 1 45 69.513a7.098 7.098 0 0 1-6.77-4.942 7.114 7.114 0 0 1-8.29-1.274 7.064 7.064 0 0 1-1.277-8.269c-2.867-.906-4.954-3.58-4.954-6.754 0-3.171 2.087-5.846 4.954-6.752a7.07 7.07 0 0 1 1.277-8.27 7.114 7.114 0 0 1 8.29-1.273A7.1 7.1 0 0 1 45 27.036a7.102 7.102 0 0 1 6.77 4.943 7.114 7.114 0 0 1 8.29 1.274 7.07 7.07 0 0 1 1.276 8.269c2.869.906 4.954 3.58 4.954 6.752a7.084 7.084 0 0 1-4.954 6.754z"/><path d="M36.484 69.514V87.92L45 83.673l8.516 4.247V69.514M45 83.673v-7.08M45 42.611V53.94M45 42.611a4.254 4.254 0 0 1-4.258 4.248M81.903 18.54H89v59.47h-7.097M89 29.868h-7.097M84.742 24.205h-2.839M8.097 18.54H1v59.47h7.097M8.097 29.868H1M8.097 24.205H5.258"/></g></svg> |
@@ -0,0 +1 @@ | |||
<svg width="58" height="56" xmlns="http://www.w3.org/2000/svg"><g fill="#4680A5" fill-rule="nonzero"><path d="M28.5 19a9.503 9.503 0 0 0-8.088 4.523 1.198 1.198 0 0 0-.102.172A9.438 9.438 0 0 0 19 28.5c0 1.353.286 2.64.798 3.806.022.061.049.12.08.177C21.388 35.737 24.684 38 28.5 38a9.498 9.498 0 0 0 7.925-4.269 1.2 1.2 0 0 0 .117-.183 9.44 9.44 0 0 0 1.453-4.822c.003-.037.005-.075.005-.114l-.002-.037L38 28.5c0-5.238-4.261-9.5-9.5-9.5zm7.127 8.464h-4.152a5.414 5.414 0 0 0-3.854 1.596l-.788.788a3.13 3.13 0 0 1-2.228.923h-2.938a7.16 7.16 0 0 1-.37-2.271 7.16 7.16 0 0 1 .73-3.156h7.28a1.15 1.15 0 0 0 0-2.298h-5.503a7.17 7.17 0 0 1 4.696-1.748c3.62 0 6.623 2.684 7.127 6.166zm-12.69 5.605h1.668a5.414 5.414 0 0 0 3.853-1.596l.788-.788a3.132 3.132 0 0 1 2.229-.923h4.114a7.147 7.147 0 0 1-.729 2.113h-2.545a1.15 1.15 0 0 0 0 2.298h.615a7.163 7.163 0 0 1-4.43 1.53 7.192 7.192 0 0 1-5.564-2.634z"/><path d="M42.177 15.924c-2.408-2.636-5.517-4.663-8.99-5.863a1.117 1.117 0 0 0-1.423.708c-.2.594.113 1.24.699 1.442 3.123 1.078 5.913 2.896 8.07 5.255 2.287 2.504 3.705 5.49 4.1 8.633.59 4.716-.915 9.5-4.13 13.127-3.111 3.509-7.465 5.503-11.985 5.503-.1 0-.2 0-.3-.003-3.427-.067-6.713-1.208-9.362-3.233.34-.625.535-1.343.535-2.107 0-2.414-1.94-4.379-4.323-4.379-.451 0-.92.072-1.33.202 0 0-1.028-1.91-1.404-5.157a16.581 16.581 0 0 1 .29-5.422c.788-3.618 2.794-6.913 5.643-9.24 1.657-1.352 3.607-2.362 5.643-2.981.593-.18.93-.813.752-1.414a1.118 1.118 0 0 0-1.395-.761c-7.101 2.158-12.34 8.447-13.154 15.923-.382 3.51.207 7.119 1.757 10.286a4.395 4.395 0 0 0-1.124 2.943c0 2.415 1.938 4.38 4.322 4.38.813 0 1.574-.23 2.225-.627 3.062 2.416 6.89 3.78 10.882 3.857.114.003.229.004.343.004 5.156 0 10.116-2.268 13.652-6.256 3.651-4.118 5.36-9.56 4.686-14.93-.454-3.617-2.071-7.037-4.679-9.89zm-29.19 23.462c0-1.162.934-2.107 2.08-2.107 1.148 0 2.082.945 2.082 2.107 0 1.163-.934 2.108-2.081 2.108-1.147 0-2.08-.945-2.08-2.108z"/><path d="M58 17.675c0-1.44-.559-2.793-1.573-3.811a5.329 5.329 0 0 0-3.799-1.579c-.51 0-1.008.072-1.486.21a28.132 28.132 0 0 0-9.442-8.84A27.836 27.836 0 0 0 27.905 0C20.45 0 13.444 2.912 8.173 8.201 2.903 13.489 0 20.521 0 28.001c0 7.478 2.902 14.51 8.173 19.798C13.443 53.088 20.451 56 27.904 56c7.454 0 14.462-2.912 19.732-8.2 5.27-5.29 8.173-12.32 8.173-19.8 0-1.89-.19-3.776-.564-5.617A5.402 5.402 0 0 0 58 17.675zm-4.93 5.373A26.04 26.04 0 0 1 53.543 28c0 6.872-2.667 13.332-7.51 18.192-4.843 4.859-11.281 7.535-18.13 7.535-6.848 0-13.286-2.676-18.13-7.535C4.934 41.332 2.267 34.872 2.267 28S4.933 14.668 9.775 9.808c4.843-4.859 11.281-7.535 18.13-7.535a25.57 25.57 0 0 1 12.674 3.358 25.852 25.852 0 0 1 8.56 7.947 5.364 5.364 0 0 0-1.882 4.097c0 1.44.558 2.793 1.573 3.811a5.39 5.39 0 0 0 4.24 1.562zm1.755-3.17c-.365.367-.798.621-1.26.767a3.13 3.13 0 0 1-3.499-1.208 3.159 3.159 0 0 1-.252-3.08 3.102 3.102 0 0 1 5.01-.885 3.127 3.127 0 0 1 0 4.407z"/><path d="M26.073 10.382c.158.385.558.639.975.617.414-.022.776-.301.905-.694a1.01 1.01 0 0 0-.344-1.1 1.013 1.013 0 0 0-1.166-.039 1.013 1.013 0 0 0-.37 1.216z"/></g></svg> |
@@ -0,0 +1 @@ | |||
<svg width="59" height="44" xmlns="http://www.w3.org/2000/svg"><g fill="#4680A5" fill-rule="nonzero"><path d="M57.025 34.892h-.064v-5.195c0-12.966-8.998-24.204-21.495-26.99A2.994 2.994 0 0 0 34.64.92 2.96 2.96 0 0 0 32.487 0h-5.974a2.96 2.96 0 0 0-2.154.92 2.995 2.995 0 0 0-.825 1.788C11.037 5.493 2.04 16.73 2.04 29.697v5.195h-.064C.885 34.892 0 35.784 0 36.88v1.309c0 .865.544 1.626 1.354 1.893C9.03 42.608 19.027 44 29.5 44c10.473 0 20.47-1.392 28.146-3.918A1.981 1.981 0 0 0 59 38.189V36.88a1.984 1.984 0 0 0-1.975-1.988zM25.735 2.257c.205-.215.482-.333.778-.333h5.974a1.085 1.085 0 0 1 1.083 1.128l-.88 25.656a1.082 1.082 0 0 1-1.082 1.053h-4.216a1.082 1.082 0 0 1-1.082-1.053l-.88-25.656c-.01-.298.098-.58.304-.795zm31.354 35.932c0 .026-.012.056-.037.064-7.49 2.465-17.275 3.823-27.552 3.823-10.277 0-20.062-1.358-27.552-3.823-.025-.009-.036-.038-.036-.064V36.88c0-.035.028-.064.063-.064h36.7c.528 0 .956-.43.956-.962a.959.959 0 0 0-.956-.962H3.95v-5.195c0-9.67 5.38-18.305 13.5-22.687l2.075 14.614a.958.958 0 0 0 1.08.816.961.961 0 0 0 .812-1.088l-2.16-15.227a25.222 25.222 0 0 1 4.317-1.452l.825 24.102a2.992 2.992 0 0 0 2.993 2.91h4.216a2.993 2.993 0 0 0 2.993-2.91l.826-24.102c1.498.358 2.941.846 4.317 1.453l-2.16 15.226a.961.961 0 0 0 .947 1.098.958.958 0 0 0 .945-.826L41.55 7.01c8.121 4.382 13.5 13.017 13.5 22.687v5.195h-6.18a.959.959 0 0 0-.956.962c0 .532.428.962.955.962h8.156c.035 0 .064.03.064.065v1.308z"/><path d="M45.032 35h-2.064c-.535 0-.968.448-.968 1s.433 1 .968 1h2.064c.535 0 .968-.448.968-1s-.433-1-.968-1zM22.987 27.896l-.397-2.065c-.102-.53-.76-.897-1.472-.821-.712.075-1.206.566-1.105 1.094l.397 2.065c.093.483.65.831 1.287.831.061 0 .123-.003.185-.01.712-.075 1.206-.565 1.105-1.094zM37.882 25.01c-.711-.076-1.37.292-1.472.82l-.397 2.066c-.101.529.393 1.019 1.105 1.094.062.007.124.01.185.01.637 0 1.194-.348 1.287-.83l.397-2.066c.101-.528-.393-1.019-1.105-1.094z"/></g></svg> |
@@ -0,0 +1 @@ | |||
<svg width="62" height="76" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><defs><path id="a" d="M0 76h62V0H0z"/></defs><g fill="none" fill-rule="evenodd"><path d="M24 37v4.667c0 .597.244 1.194.733 1.65A2.584 2.584 0 0 0 26.5 44c.64 0 1.279-.227 1.767-.684a2.246 2.246 0 0 0 .733-1.65V37" stroke="#236A97" stroke-width="2"/><path d="M28 37v5.714c0 .585.244 1.17.733 1.616.488.447 1.127.67 1.767.67.64 0 1.279-.223 1.767-.67A2.18 2.18 0 0 0 33 42.714V37M33 36.53v14.117c0 .602.244 1.205.733 1.664.488.46 1.127.689 1.767.689.64 0 1.279-.23 1.767-.69A2.273 2.273 0 0 0 38 50.648V33" stroke="#236A97" stroke-width="2"/><path d="M23.8 36.958v3.625c0 .619-.234 1.238-.703 1.709A2.382 2.382 0 0 1 21.4 43a2.382 2.382 0 0 1-1.697-.708A2.414 2.414 0 0 1 19 40.583V23.667L21.4 14h16.8v3.625l4.8 8.458v7.25c0 .619-.234 1.238-.703 1.709a2.382 2.382 0 0 1-1.697.708 2.382 2.382 0 0 1-1.697-.708 2.414 2.414 0 0 1-.703-1.709V28.5M40 0v14H19V0M36 10V8M56 47V29M60 41l-4.5 5-4.5-5M56 26v-2M56 21v-2M6 47V29M10 41l-4.5 5L1 41M6 26v-2M6 21v-2M41.8 54h18c.307 0 .614.114.848.342.234.227.352.526.352.825v18.666c0 .299-.118.598-.352.825A1.214 1.214 0 0 1 59.8 75H2.2c-.307 0-.614-.114-.848-.342A1.147 1.147 0 0 1 1 73.833V55.167c0-.299.118-.598.352-.825.234-.228.54-.342.848-.342h27.6M25 64h2M30 64h2M35 64h2" stroke="#236A97" stroke-width="2"/><mask id="b" fill="#fff"><use xlink:href="#a"/></mask><path stroke="#236A97" stroke-width="2" mask="url(#b)" d="M6 70h50V58H6z"/></g></svg> |
@@ -0,0 +1 @@ | |||
<svg width="62" height="62" xmlns="http://www.w3.org/2000/svg"><g fill="#4680A5" fill-rule="nonzero"><path d="M32.561 29.44a1.5 1.5 0 1 0-2.122 2.12 1.5 1.5 0 0 0 2.122-2.12zM48.241 13.759a5.998 5.998 0 0 0-8.487 0 6.01 6.01 0 0 0 0 8.487 6.009 6.009 0 0 0 8.487 0 5.998 5.998 0 0 0 0-8.487zm-1.697 6.79a3.605 3.605 0 0 1-5.092 0 3.606 3.606 0 0 1 0-5.093 3.599 3.599 0 0 1 5.092 0 3.599 3.599 0 0 1 0 5.092z"/><path d="M61.648.352a1.198 1.198 0 0 0-.893-.351c-.272.01-6.743.27-14.435 2.988-6.164 2.177-11.301 5.293-15.27 9.262a45.74 45.74 0 0 0-2.583 2.812c-3.924-2.31-7.069-1.586-9.057-.522-4.577 2.45-7.41 9.1-7.41 13.858a1.202 1.202 0 0 0 2.052.85c2.414-2.414 5.392-2.263 6.364-2.135l.421.421a42.277 42.277 0 0 0-1.985 5.838c-.177.69-.117 1.42.146 2.088a11.383 11.383 0 0 0-3.246 2.288c-3.094 3.094-3.723 10.635-3.748 10.954a1.202 1.202 0 0 0 1.293 1.293c.32-.025 7.86-.653 10.954-3.747a11.383 11.383 0 0 0 2.288-3.245 3.394 3.394 0 0 0 2.09.144 42.282 42.282 0 0 0 5.836-1.985l.421.421c.128.973.279 3.95-2.135 6.364a1.202 1.202 0 0 0 .85 2.052c4.757 0 11.409-2.833 13.858-7.41 1.064-1.988 1.788-5.133-.522-9.057a45.756 45.756 0 0 0 2.813-2.583c3.969-3.969 7.084-9.107 9.26-15.27C61.73 7.988 61.99 1.517 62 1.245a1.202 1.202 0 0 0-.352-.893zm-46.96 25.462c.746-3.614 2.915-7.579 5.857-9.154 1.967-1.052 4.116-.949 6.401.302a48.6 48.6 0 0 0-5.05 8.232c-.018-.01-.234-.283-.636-.374-.166-.037-3.346-.72-6.573.994zm7.863 18.735c-1.653 1.653-5.53 2.524-7.98 2.88.356-2.45 1.228-6.327 2.88-7.98.926-.925 2-1.627 3.078-2.022l4.045 4.045c-.396 1.078-1.097 2.151-2.023 3.077zm5.48-3.73c-.348.09-.75-.041-1.05-.34a22337.974 22337.974 0 0 0-5.459-5.459c-.3-.3-.43-.703-.341-1.05a39.03 39.03 0 0 1 1.5-4.59l9.94 9.939a39.003 39.003 0 0 1-4.59 1.5zm17.309.636c-1.575 2.942-5.54 5.111-9.153 5.858 1.152-2.168 1.406-4.928.985-6.602-.098-.388-.351-.584-.366-.607a48.618 48.618 0 0 0 8.232-5.05c1.251 2.286 1.354 4.435.302 6.401zm2.71-12.205a43.628 43.628 0 0 1-3.467 3.11 46.18 46.18 0 0 1-9.581 5.94L23.7 27a46.172 46.172 0 0 1 5.94-9.583 43.619 43.619 0 0 1 3.11-3.467c3.56-3.56 8.156-6.395 13.662-8.435l10.072 10.072c-2.04 5.506-4.874 10.102-8.435 13.663zm9.3-16.198L48.948 4.65c4.578-1.422 8.56-1.954 10.547-2.146-.191 1.988-.724 5.97-2.145 10.547z"/><path d="M28.636 50.364a1.243 1.243 0 0 0-1.758 0l-3.514 3.515a1.242 1.242 0 1 0 1.758 1.757l3.514-3.515a1.242 1.242 0 0 0 0-1.757zM11.636 33.364a1.242 1.242 0 0 0-1.757 0l-3.515 3.514a1.243 1.243 0 0 0 1.757 1.758l3.515-3.514a1.243 1.243 0 0 0 0-1.758zM20.666 52.334a1.14 1.14 0 0 0-1.612 0l-7.72 7.72a1.14 1.14 0 0 0 1.612 1.612l7.72-7.72a1.14 1.14 0 0 0 0-1.612zM10.666 52.334a1.14 1.14 0 0 0-1.612 0l-7.72 7.72a1.14 1.14 0 0 0 1.612 1.612l7.72-7.72a1.14 1.14 0 0 0 0-1.612zM9.666 41.334a1.14 1.14 0 0 0-1.612 0l-7.72 7.72a1.14 1.14 0 1 0 1.612 1.612l7.72-7.72a1.14 1.14 0 0 0 0-1.612zM37.657 24.343a1.172 1.172 0 0 0-1.657 0L34.343 26A1.172 1.172 0 0 0 36 27.657L37.657 26c.457-.457.457-1.2 0-1.657z"/></g></svg> |
@@ -17,8 +17,9 @@ | |||
* along with this program; if not, write to the Free Software Foundation, | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import { getJSON, postJSON, post, requestTryAndRepeatUntil } from '../helpers/request'; | |||
import { getJSON, postJSON, post, requestTryAndRepeatUntil, getCorsJSON } from '../helpers/request'; | |||
import throwGlobalError from '../app/utils/throwGlobalError'; | |||
import { AlmLanguagesStats } from '../apps/tutorials/analyzeProject/utils'; | |||
export function bindAlmOrganization(data: { installationId: string; organization: string }) { | |||
return post('/api/alm_integration/bind_organization', data).catch(throwGlobalError); | |||
@@ -75,3 +76,9 @@ export function provisionProject(data: { | |||
installationKeys: data.installationKeys.join(',') | |||
}).catch(throwGlobalError); | |||
} | |||
export function getGithubLanguages(url: string): Promise<AlmLanguagesStats> { | |||
// We don't want to throwGlobalError | |||
const apiUrl = url.replace('https://github.com/', 'https://api.github.com/repos/'); | |||
return getCorsJSON(`${apiUrl}/languages`); | |||
} |
@@ -53,6 +53,10 @@ | |||
margin-left: 20px; | |||
} | |||
.flex-column-full { | |||
width: 100%; | |||
} | |||
.flex-column-half { | |||
width: 50%; | |||
} |
@@ -136,7 +136,8 @@ | |||
} | |||
.rule-desc code, | |||
.markdown code { | |||
.markdown code, | |||
code.rule { | |||
padding: 0.2em 0.45em; | |||
margin: 0; | |||
background-color: rgba(0, 0, 0, 0.06); |
@@ -23,6 +23,7 @@ import { createHistory, History } from 'history'; | |||
let history: History; | |||
function ensureHistory() { | |||
// eslint-disable-next-line react-hooks/rules-of-hooks | |||
history = useRouterHistory(createHistory)({ | |||
// do not use `getBaseUrl` from `helpers/urls` to no import this file with all its dependecies | |||
basename: (window as any).baseUrl |
@@ -60,7 +60,7 @@ it('should render correctly', async () => { | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('should render with Manual creation only', () => { | |||
it('should render with Custom creation only', () => { | |||
expect(getWrapper({ currentUser: { ...user, externalProvider: 'microsoft' } })).toMatchSnapshot(); | |||
}); | |||
@@ -100,7 +100,7 @@ exports[`should render correctly 2`] = ` | |||
</Fragment> | |||
`; | |||
exports[`should render with Manual creation only 1`] = ` | |||
exports[`should render with Custom creation only 1`] = ` | |||
<Fragment> | |||
<HelmetWrapper | |||
defer={true} |
@@ -20,13 +20,15 @@ | |||
import * as React from 'react'; | |||
import { Helmet } from 'react-helmet'; | |||
import OverviewApp from './OverviewApp'; | |||
import EmptyOverview from './EmptyOverview'; | |||
import ReviewApp from '../pullRequests/ReviewApp'; | |||
import Suggestions from '../../../app/components/embed-docs-modal/Suggestions'; | |||
import { withRouter, Router } from '../../../components/hoc/withRouter'; | |||
import { getProjectUrl, getBaseUrl, getPathUrlAsString } from '../../../helpers/urls'; | |||
import { isSonarCloud } from '../../../helpers/system'; | |||
import { isShortLivingBranch, isPullRequest } from '../../../helpers/branches'; | |||
import { lazyLoad } from '../../../components/lazyLoad'; | |||
const EmptyOverview = lazyLoad(() => import('./EmptyOverview')); | |||
interface Props { | |||
branchLike?: T.BranchLike; |
@@ -21,12 +21,14 @@ import * as React from 'react'; | |||
import { connect } from 'react-redux'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import AnalyzeTutorial from '../../tutorials/analyzeProject/AnalyzeTutorial'; | |||
import AnalyzeTutorialSonarCloud from '../../tutorials/analyzeProject/AnalyzeTutorialSonarCloud'; | |||
import MetaContainer from '../meta/MetaContainer'; | |||
import { isLongLivingBranch, isBranch, isMainBranch } from '../../../helpers/branches'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { isLoggedIn } from '../../../helpers/users'; | |||
import { getCurrentUser, Store } from '../../../store/rootReducer'; | |||
import { Alert } from '../../../components/ui/Alert'; | |||
import { isSonarCloud } from '../../../helpers/system'; | |||
interface OwnProps { | |||
branchLike?: T.BranchLike; | |||
@@ -70,9 +72,13 @@ export function EmptyOverview({ | |||
} | |||
/> | |||
)} | |||
{!hasBranches && !hasAnalyses && ( | |||
<AnalyzeTutorial component={component} currentUser={currentUser} /> | |||
)} | |||
{!hasBranches && | |||
!hasAnalyses && | |||
(isSonarCloud() ? ( | |||
<AnalyzeTutorialSonarCloud component={component} currentUser={currentUser} /> | |||
) : ( | |||
<AnalyzeTutorial component={component} currentUser={currentUser} /> | |||
))} | |||
</> | |||
) : ( | |||
<WarningMessage | |||
@@ -82,13 +88,15 @@ export function EmptyOverview({ | |||
)} | |||
</div> | |||
<div className="overview-sidebar page-sidebar-fixed"> | |||
<MetaContainer | |||
branchLike={branchLike} | |||
component={component} | |||
onComponentChange={onComponentChange} | |||
/> | |||
</div> | |||
{!isSonarCloud() && ( | |||
<div className="overview-sidebar page-sidebar-fixed"> | |||
<MetaContainer | |||
branchLike={branchLike} | |||
component={component} | |||
onComponentChange={onComponentChange} | |||
/> | |||
</div> | |||
)} | |||
</div> | |||
</div> | |||
); |
@@ -47,14 +47,6 @@ it('should render OverviewApp', () => { | |||
).toBeTruthy(); | |||
}); | |||
it('should render EmptyOverview', () => { | |||
expect( | |||
getWrapper({ component: { key: 'foo' } as T.Component }) | |||
.find('Connect(EmptyOverview)') | |||
.exists() | |||
).toBeTruthy(); | |||
}); | |||
function getWrapper(props = {}) { | |||
return shallow( | |||
<App |
@@ -0,0 +1,44 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import { getUniqueTokenName } from '../utils'; | |||
const initialTokenName = 'Analyze "lightsaber"'; | |||
it('should return the given name when the user has no token', () => { | |||
const userTokens: T.UserToken[] = []; | |||
expect(getUniqueTokenName(userTokens, initialTokenName)).toBe(initialTokenName); | |||
}); | |||
it('should generate a token with the given name', () => { | |||
const userTokens = [{ name: initialTokenName, createdAt: '2019-06-14T09:45:52+0200' }]; | |||
expect(getUniqueTokenName(userTokens, 'Analyze "project"')).toBe('Analyze "project"'); | |||
}); | |||
it('should generate a unique token when the name already exists', () => { | |||
const userTokens = [ | |||
{ name: initialTokenName, createdAt: '2019-06-14T09:45:52+0200' }, | |||
{ name: `${initialTokenName} 1`, createdAt: '2019-06-14T09:45:52+0200' } | |||
]; | |||
expect(getUniqueTokenName(userTokens, initialTokenName)).toBe('Analyze "lightsaber" 2'); | |||
}); |
@@ -27,7 +27,7 @@ import InstanceMessage from '../../../components/common/InstanceMessage'; | |||
import { isSonarCloud } from '../../../helpers/system'; | |||
import '../styles.css'; | |||
enum Steps { | |||
export enum Steps { | |||
ANALYSIS, | |||
TOKEN | |||
} |
@@ -0,0 +1,119 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
.page-analysis { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
margin: 0 auto; | |||
} | |||
.page-analysis .page-header { | |||
text-align: center; | |||
} | |||
.page-analysis h1 { | |||
font-weight: bold; | |||
} | |||
.page-analysis-container-sonarcloud .onboarding-step { | |||
padding: 0 calc(var(--gridSize) * 4); | |||
} | |||
.analysis-selector { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: space-around; | |||
} | |||
.analysis-modes { | |||
display: flex; | |||
justify-content: space-around; | |||
width: 80%; | |||
} | |||
.mode-type { | |||
display: flex; | |||
flex-direction: column; | |||
justify-content: center; | |||
align-items: center; | |||
} | |||
.mode-type .icon { | |||
position: relative; | |||
display: flex; | |||
align-items: center; | |||
justify-content: center; | |||
width: 100px; | |||
height: 100px; | |||
background-repeat: no-repeat; | |||
background-position: center; | |||
} | |||
.mode-type .name { | |||
font-weight: bold; | |||
} | |||
.mode-type-autoscan { | |||
padding: calc(var(--gridSize) * 6) calc(var(--gridSize) * 10); | |||
background: white; | |||
box-shadow: 0 0 10px 0 rgba(0, 0, 0, 0.3); | |||
} | |||
.mode-type-autoscan .icon { | |||
background-image: url(/images/sonarcloud-square-logo.svg); | |||
} | |||
.mode-type-autoscan .icon .badge { | |||
position: absolute; | |||
top: 12px; | |||
right: 0; | |||
} | |||
.mode-type-travis .icon { | |||
background-image: url(/images/sonarcloud/analysis/helmet.svg); | |||
} | |||
.mode-type-other .icon { | |||
background-image: url(/images/sonarcloud/analysis/galaxy.svg); | |||
} | |||
.mode-type-manual .icon { | |||
background-image: url(/images/sonarcloud/analysis/manual.svg); | |||
} | |||
.step-selector { | |||
display: flex; | |||
} | |||
.page-analysis-waiting { | |||
text-align: center; | |||
} | |||
.page-analysis-waiting .links { | |||
padding: calc(var(--gridSize) * 6) calc(var(--gridSize) * 10); | |||
background: white; | |||
} | |||
.onboarding-step hr.no-horizontal-margins { | |||
margin-left: 0; | |||
margin-right: 0; | |||
} |
@@ -0,0 +1,364 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as classnames from 'classnames'; | |||
import * as React from 'react'; | |||
import ConfigureWithAutoScan from './configurations/ConfigureWithAutoScan'; | |||
import ConfigureWithTravis from './configurations/ConfigureWithTravis'; | |||
import ConfigureWithLocalScanner from './configurations/ConfigureWithLocalScanner'; | |||
import ConfigureOtherCI from './configurations/ConfigureWithOtherCI'; | |||
import { TutorialSuggestionBitbucket, TutorialSuggestionVSTS } from './AnalyzeTutorialSuggestion'; | |||
import { | |||
Alm, | |||
ALM_KEYS, | |||
AlmLanguagesStats, | |||
alms, | |||
AnalysisMode, | |||
autoScanMode, | |||
isAutoScannable, | |||
modes, | |||
PROJECT_ONBOARDING_DONE, | |||
PROJECT_ONBOARDING_MODE_ID, | |||
PROJECT_STEP_PROGRESS, | |||
TutorialProps | |||
} from './utils'; | |||
import { getUniqueTokenName } from '../utils'; | |||
import AnalyzeTutorialDone from '../components/AnalyzeTutorialDone'; | |||
import InstanceMessage from '../../../components/common/InstanceMessage'; | |||
import BackButton from '../../../components/controls/BackButton'; | |||
import TokenStep from '../components/TokenStep'; | |||
import ProjectAnalysisStep from '../components/ProjectAnalysisStep'; | |||
import { generateToken, getTokens } from '../../../api/user-tokens'; | |||
import { getGithubLanguages } from '../../../api/alm-integration'; | |||
import { isBitbucket, isGithub, isVSTS } from '../../../helpers/almIntegrations'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { get, remove, save } from '../../../helpers/storage'; | |||
import { isSonarCloud } from '../../../helpers/system'; | |||
import '../styles.css'; | |||
import './AnalyzeTutorialSonarCloud.css'; | |||
import DeferredSpinner from '../../../components/common/DeferredSpinner'; | |||
interface Props { | |||
component: T.Component; | |||
currentUser: T.LoggedInUser; | |||
} | |||
const tutorials: { | |||
[k: string]: (props: Props & TutorialProps) => JSX.Element; | |||
} = { | |||
autoscan: ConfigureWithAutoScan, | |||
manual: ConfigureWithLocalScanner, | |||
other: ConfigureOtherCI, | |||
travis: ConfigureWithTravis | |||
}; | |||
enum Steps { | |||
ANALYSIS = 'ANALYSIS', | |||
TOKEN = 'TOKEN' | |||
} | |||
interface State { | |||
alm?: Alm; | |||
almLanguageStats?: AlmLanguagesStats; | |||
isTutorialDone: boolean; | |||
mode?: AnalysisMode; | |||
loading: boolean; | |||
step: Steps; | |||
token?: string; | |||
} | |||
export default class AnalyzeTutorialSonarCloud extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
constructor(props: Props) { | |||
super(props); | |||
this.state = { | |||
loading: true, | |||
isTutorialDone: get(PROJECT_ONBOARDING_DONE, props.component.key) === 'true', | |||
step: Steps.TOKEN | |||
}; | |||
} | |||
componentDidMount() { | |||
this.mounted = true; | |||
const { component, currentUser } = this.props; | |||
const almKey = (component.alm && component.alm.key) || currentUser.externalProvider; | |||
if (!almKey) { | |||
return; | |||
} | |||
if (isBitbucket(almKey)) { | |||
this.configureBitbucket(); | |||
} else if (isGithub(almKey)) { | |||
this.configureGithub(); | |||
} else if (isVSTS(almKey)) { | |||
this.configureMicrosoft(); | |||
} | |||
if (currentUser) { | |||
getTokens(currentUser.login).then( | |||
t => { | |||
this.getNewToken(getUniqueTokenName(t, `Analyze "${component.name}"`)); | |||
}, | |||
() => {} | |||
); | |||
} | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
configureBitbucket = () => { | |||
this.setState({ alm: alms[ALM_KEYS.BITBUCKET], loading: false }); | |||
}; | |||
configureGithub = () => { | |||
const { component } = this.props; | |||
this.setState({ | |||
alm: alms[ALM_KEYS.GITHUB] | |||
}); | |||
const savedModeId = get(PROJECT_ONBOARDING_MODE_ID, component.key); | |||
const mode = | |||
autoScanMode.id === savedModeId ? autoScanMode : modes.find(m => m.id === savedModeId); | |||
if (mode) { | |||
this.setState({ mode }); | |||
} | |||
if (!component.alm) { | |||
return; | |||
} | |||
const { url } = component.alm; | |||
if (!url) { | |||
return; | |||
} | |||
getGithubLanguages(url).then( | |||
almLanguagesStats => { | |||
if (this.mounted) { | |||
this.setState({ | |||
almLanguageStats: almLanguagesStats, | |||
loading: false | |||
}); | |||
} | |||
}, | |||
() => { | |||
this.setState({ loading: false }); | |||
} | |||
); | |||
}; | |||
configureMicrosoft = () => { | |||
this.setState({ alm: alms[ALM_KEYS.MICROSOFT], loading: false }); | |||
}; | |||
getNewToken = (tokenName: string) => { | |||
generateToken({ name: tokenName }).then( | |||
({ token }: { token: string }) => { | |||
this.setToken(token); | |||
}, | |||
() => {} | |||
); | |||
}; | |||
setToken = (token: string) => { | |||
if (this.mounted) { | |||
this.setState({ token }); | |||
} | |||
}; | |||
setTutorialDone = (value: boolean) => { | |||
save(PROJECT_ONBOARDING_DONE, String(value), this.props.component.key); | |||
this.setState({ isTutorialDone: value }); | |||
}; | |||
spinner = () => ( | |||
<div className="display-flex-justify-center spinner-margin"> | |||
<i className="spinner global-loading-spinner" /> | |||
</div> | |||
); | |||
renderBitbucket = () => { | |||
const { component, currentUser } = this.props; | |||
const { step, token } = this.state; | |||
const handleTokenDone = (t: string) => { | |||
if (this.mounted) { | |||
this.setState({ | |||
step: Steps.ANALYSIS, | |||
token: t | |||
}); | |||
} | |||
}; | |||
const handleTokenOpen = () => { | |||
this.setState({ step: Steps.TOKEN }); | |||
}; | |||
return ( | |||
<> | |||
<TutorialSuggestionBitbucket /> | |||
<TokenStep | |||
currentUser={currentUser} | |||
finished={Boolean(token)} | |||
initialTokenName={`Analyze "${component.name}"`} | |||
onContinue={handleTokenDone} | |||
onOpen={handleTokenOpen} | |||
open={step === Steps.TOKEN} | |||
stepNumber={1} | |||
/> | |||
<ProjectAnalysisStep | |||
component={component} | |||
displayRowLayout={true} | |||
open={step === Steps.ANALYSIS} | |||
organization={isSonarCloud() ? component.organization : undefined} | |||
stepNumber={2} | |||
token={token} | |||
/> | |||
</> | |||
); | |||
}; | |||
renderGithub = () => { | |||
const { almLanguageStats, isTutorialDone, mode, token } = this.state; | |||
if (isTutorialDone) { | |||
return <AnalyzeTutorialDone setTutorialDone={this.setTutorialDone} />; | |||
} | |||
const { component, currentUser } = this.props; | |||
const Tutorial = mode && tutorials[mode.id]; | |||
const getClassnames = (item: AnalysisMode) => | |||
classnames(`mode-type mode-type-${item.id}`, { | |||
[`mode-type-selected`]: mode && mode.id === item.id | |||
}); | |||
const isAutoScanEnabled = | |||
almLanguageStats && isAutoScannable(almLanguageStats).withAllowedLanguages; | |||
const setMode = (mode: AnalysisMode | undefined) => { | |||
if (mode) { | |||
save(PROJECT_ONBOARDING_MODE_ID, mode.id, component.key); | |||
remove(PROJECT_STEP_PROGRESS, component.key); | |||
} else { | |||
remove(PROJECT_ONBOARDING_MODE_ID, component.key); | |||
} | |||
this.setState({ mode }); | |||
}; | |||
if (!mode || !Tutorial) { | |||
return ( | |||
<div className="page-analysis-container page-analysis-container-sonarcloud"> | |||
<div className="page-analysis big-spacer-top big-spacer-bottom huge-spacer-left huge-spacer-right"> | |||
<div className="page-header big-spacer-bottom"> | |||
<h1 className="big-spacer-bottom"> | |||
{translate('onboarding.project_analysis.header')} | |||
</h1> | |||
<p> | |||
<InstanceMessage message={translate('onboarding.project_analysis.description')} /> | |||
</p> | |||
</div> | |||
{isAutoScanEnabled && ( | |||
<div className={`${getClassnames(autoScanMode)} huge-spacer-top huge-spacer-bottom`}> | |||
<div className="icon"> | |||
<div className="badge badge-new">BETA</div> | |||
</div> | |||
<p>{autoScanMode.name}</p> | |||
<button | |||
className="button big-spacer-top big-spacer-bottom" | |||
onClick={() => setMode(autoScanMode)} | |||
type="button"> | |||
{translate('projects.configure_analysis')} | |||
</button> | |||
</div> | |||
)} | |||
<div className="analysis-modes"> | |||
{modes.map(el => ( | |||
<div className={getClassnames(el)} key={el.id}> | |||
<div className="icon" /> | |||
<div className="name">{el.name}</div> | |||
<button | |||
className="button big-spacer-top big-spacer-bottom" | |||
onClick={() => setMode(el)} | |||
type="button"> | |||
{translate('projects.configure_analysis')} | |||
</button> | |||
</div> | |||
))} | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} | |||
return ( | |||
<div className="page-analysis-container page-analysis-container-sonarcloud"> | |||
<BackButton | |||
onClick={() => setMode(undefined)} | |||
tooltip={translate('onboarding.tutorial.return_to_list')}> | |||
{translate('back')} | |||
</BackButton> | |||
<Tutorial | |||
component={component} | |||
currentUser={currentUser} | |||
onDone={() => this.setTutorialDone(true)} | |||
setToken={this.setToken} | |||
token={token} | |||
/> | |||
</div> | |||
); | |||
}; | |||
renderMicrosoft = () => { | |||
return <TutorialSuggestionVSTS />; | |||
}; | |||
render() { | |||
const { alm, loading } = this.state; | |||
if (!alm) { | |||
return null; | |||
} | |||
return ( | |||
<DeferredSpinner customSpinner={<this.spinner />} loading={loading}> | |||
{!loading && ( | |||
<> | |||
{alm.id === ALM_KEYS.BITBUCKET && this.renderBitbucket()} | |||
{alm.id === ALM_KEYS.GITHUB && this.renderGithub()} | |||
{alm.id === ALM_KEYS.MICROSOFT && this.renderMicrosoft()} | |||
</> | |||
)} | |||
</DeferredSpinner> | |||
); | |||
} | |||
} |
@@ -24,71 +24,83 @@ import { translate } from '../../../helpers/l10n'; | |||
import { getBaseUrl } from '../../../helpers/urls'; | |||
import { Alert } from '../../../components/ui/Alert'; | |||
export function TutorialSuggestionBitbucket() { | |||
return ( | |||
<Alert className="big-spacer-bottom" variant="info"> | |||
<p>{translate('onboarding.project_analysis.commands_for_analysis')}</p> | |||
<p>{translate('onboarding.project_analysis.suggestions.bitbucket')}</p> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.project_analysis.simply_link')} | |||
id={'onboarding.project_analysis.simply_link'} | |||
values={{ | |||
link: ( | |||
<a | |||
href={ | |||
getBaseUrl() + | |||
'/documentation/integrations/bitbucketcloud/#analyzing-with-pipelines' | |||
} | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.project_analysis.guide_to_integrate_pipelines')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</Alert> | |||
); | |||
} | |||
export function TutorialSuggestionGithub() { | |||
return ( | |||
<Alert className="big-spacer-bottom" variant="info"> | |||
<p>{translate('onboarding.project_analysis.commands_for_analysis')} </p> | |||
<p>{translate('onboarding.project_analysis.suggestions.github')}</p> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.project_analysis.simply_link')} | |||
id={'onboarding.project_analysis.simply_link'} | |||
values={{ | |||
link: ( | |||
<a | |||
href="https://docs.travis-ci.com/user/sonarcloud/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.project_analysis.guide_to_integrate_travis')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</Alert> | |||
); | |||
} | |||
export function TutorialSuggestionVSTS() { | |||
return ( | |||
<Alert className="big-spacer-bottom" variant="info"> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.project_analysis.simply_link')} | |||
id={'onboarding.project_analysis.simply_link'} | |||
values={{ | |||
link: ( | |||
<a | |||
href={getBaseUrl() + '/documentation/integrations/vsts/'} | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.project_analysis.guide_to_integrate_vsts')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</Alert> | |||
); | |||
} | |||
export default function AnalyzeTutorialSuggestion({ almKey }: { almKey?: string }) { | |||
if (isBitbucket(almKey)) { | |||
return ( | |||
<Alert className="big-spacer-bottom" variant="info"> | |||
<p>{translate('onboarding.project_analysis.commands_for_analysis')}</p> | |||
<p>{translate('onboarding.project_analysis.suggestions.bitbucket')}</p> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.project_analysis.simply_link')} | |||
id={'onboarding.project_analysis.simply_link'} | |||
values={{ | |||
link: ( | |||
<a | |||
href={ | |||
getBaseUrl() + | |||
'/documentation/integrations/bitbucketcloud/#analyzing-with-pipelines' | |||
} | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.project_analysis.guide_to_integrate_piplines')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</Alert> | |||
); | |||
return <TutorialSuggestionBitbucket />; | |||
} else if (isGithub(almKey)) { | |||
return ( | |||
<Alert className="big-spacer-bottom" variant="info"> | |||
<p>{translate('onboarding.project_analysis.commands_for_analysis')} </p> | |||
<p>{translate('onboarding.project_analysis.suggestions.github')}</p> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.project_analysis.simply_link')} | |||
id={'onboarding.project_analysis.simply_link'} | |||
values={{ | |||
link: ( | |||
<a | |||
href="https://docs.travis-ci.com/user/sonarcloud/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.project_analysis.guide_to_integrate_travis')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</Alert> | |||
); | |||
return <TutorialSuggestionGithub />; | |||
} else if (isVSTS(almKey)) { | |||
return ( | |||
<Alert className="big-spacer-bottom" variant="info"> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.project_analysis.simply_link')} | |||
id={'onboarding.project_analysis.simply_link'} | |||
values={{ | |||
link: ( | |||
<a | |||
href={getBaseUrl() + '/documentation/integrations/vsts/'} | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.project_analysis.guide_to_integrate_vsts')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</Alert> | |||
); | |||
return <TutorialSuggestionVSTS />; | |||
} | |||
return null; | |||
} |
@@ -0,0 +1,177 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import AnalyzeTutorialSonarCloud from '../AnalyzeTutorialSonarCloud'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks'; | |||
import { get } from '../../../../helpers/storage'; | |||
import { waitAndUpdate } from '../../../../helpers/testUtils'; | |||
import { generateToken, getTokens } from '../../../../api/user-tokens'; | |||
import { getUniqueTokenName } from '../../utils'; | |||
jest.mock('../../../../helpers/storage', () => ({ | |||
get: jest.fn(), | |||
remove: jest.fn(), | |||
save: jest.fn() | |||
})); | |||
jest.mock('../../../../api/alm-integration', () => ({ | |||
getGithubLanguages: jest.fn().mockResolvedValue({ | |||
JavaScript: 512636, | |||
TypeScript: 425475, | |||
HTML: 390075, | |||
CSS: 14099, | |||
Makefile: 536, | |||
Dockerfile: 319 | |||
}) | |||
})); | |||
jest.mock('../../../../api/user-tokens', () => ({ | |||
generateToken: jest.fn().mockResolvedValue({ | |||
name: 'baz', | |||
createdAt: '2019-01-21T08:06:00+0100', | |||
login: 'luke', | |||
token: 'token_value' | |||
}), | |||
getTokens: jest.fn().mockResolvedValue([ | |||
{ | |||
name: 'foo', | |||
createdAt: '2019-01-15T15:06:33+0100', | |||
lastConnectionDate: '2019-01-18T15:06:33+0100' | |||
}, | |||
{ name: 'bar', createdAt: '2019-01-18T15:06:33+0100' } | |||
]), | |||
revokeToken: jest.fn().mockResolvedValue(Promise.resolve()) | |||
})); | |||
jest.mock('../../utils', () => ({ | |||
getUniqueTokenName: jest.fn().mockReturnValue('lightsaber-9000') | |||
})); | |||
const component = mockComponent(); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('shows a loading screen', () => { | |||
expect(shallowRender() | |||
.find('DeferredSpinner') | |||
.prop('loading') as boolean).toBe(true); | |||
}); | |||
it('renders for GitHub', async () => { | |||
const comp = { | |||
...component, | |||
alm: { key: 'github', url: 'https://github.com/luke/lightsaber' } | |||
}; | |||
const wrapper = shallowRender({ component: comp }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
wrapper | |||
.find('button') | |||
.first() | |||
.simulate('click'); | |||
expect(wrapper.state('mode')).toEqual({ | |||
id: 'autoscan', | |||
name: 'SonarCloud Automatic Analysis' | |||
}); | |||
}); | |||
it('renders for BitBucket', () => { | |||
const comp = { | |||
...component, | |||
alm: { key: 'bitbucket', url: 'https://bitbucket.com/luke/lightsaber' } | |||
}; | |||
const wrapper = shallowRender({ component: comp }); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper.find('TokenStep').prop('onContinue') as Function)('abc123'); | |||
expect(wrapper.state('token')).toBe('abc123'); | |||
expect(wrapper.state('step')).toBe('ANALYSIS'); | |||
}); | |||
it('renders for Azure', () => { | |||
const comp = { | |||
...component, | |||
alm: { key: 'microsoft', url: 'https://azuredevops.com/luke/lightsaber' } | |||
}; | |||
expect(shallowRender({ component: comp })).toMatchSnapshot(); | |||
}); | |||
it('renders for a non supported component', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper).toMatchSnapshot(); | |||
}); | |||
it('renders the finished state', async () => { | |||
(get as jest.Mock).mockReturnValue('true'); | |||
const comp = { | |||
...component, | |||
alm: { key: 'github', url: 'https://github.com/luke/lightsaber' } | |||
}; | |||
const wrapper = shallowRender({ component: comp }); | |||
await waitAndUpdate(wrapper); | |||
expect(wrapper.find('AnalyzeTutorialDone').exists()).toBe(true); | |||
}); | |||
it('should get tokens and unique name', async () => { | |||
const wrapper = shallowRender(); | |||
await waitAndUpdate(wrapper); | |||
expect(getTokens).toHaveBeenCalled(); | |||
expect(getUniqueTokenName).toHaveBeenCalled(); | |||
expect(generateToken).toHaveBeenCalled(); | |||
expect(wrapper.state('token')).toBe('token_value'); | |||
}); | |||
it('should set tutorial done', () => { | |||
const wrapper = shallowRender(); | |||
const instance = wrapper.instance(); | |||
instance.setTutorialDone(false); | |||
expect(wrapper.state('isTutorialDone')).toBeFalsy(); | |||
instance.setTutorialDone(true); | |||
expect(wrapper.state('isTutorialDone')).toBeTruthy(); | |||
}); | |||
it('should have a spinner', () => { | |||
const wrapper = shallowRender(); | |||
const instance = wrapper.instance(); | |||
expect(instance.spinner()).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<AnalyzeTutorialSonarCloud['props']> = {}) { | |||
return shallow<AnalyzeTutorialSonarCloud>( | |||
<AnalyzeTutorialSonarCloud | |||
component={component} | |||
currentUser={mockLoggedInUser({ externalProvider: 'github' })} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -19,20 +19,42 @@ | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import AnalyzeTutorialSuggestion from '../AnalyzeTutorialSuggestion'; | |||
import AnalyzeTutorialSuggestion, { | |||
TutorialSuggestionBitbucket, | |||
TutorialSuggestionGithub, | |||
TutorialSuggestionVSTS | |||
} from '../AnalyzeTutorialSuggestion'; | |||
it('should not render', () => { | |||
expect(shallow(<AnalyzeTutorialSuggestion almKey={undefined} />).type()).toBeNull(); | |||
}); | |||
it('renders bitbucket suggestions correctly', () => { | |||
expect(shallow(<AnalyzeTutorialSuggestion almKey="bitbucket" />)).toMatchSnapshot(); | |||
expect( | |||
shallow(<AnalyzeTutorialSuggestion almKey="bitbucket" />).find(TutorialSuggestionBitbucket) | |||
).toHaveLength(1); | |||
}); | |||
it('renders github suggestions correctly', () => { | |||
expect(shallow(<AnalyzeTutorialSuggestion almKey="github" />)).toMatchSnapshot(); | |||
expect( | |||
shallow(<AnalyzeTutorialSuggestion almKey="github" />).find(TutorialSuggestionGithub) | |||
).toHaveLength(1); | |||
}); | |||
it('renders vsts suggestions correctly', () => { | |||
expect(shallow(<AnalyzeTutorialSuggestion almKey="microsoft" />)).toMatchSnapshot(); | |||
expect( | |||
shallow(<AnalyzeTutorialSuggestion almKey="microsoft" />).find(TutorialSuggestionVSTS) | |||
).toHaveLength(1); | |||
}); | |||
it('renders bitbucket tutorial correctly', () => { | |||
expect(shallow(<TutorialSuggestionBitbucket />)).toMatchSnapshot(); | |||
}); | |||
it('renders github tutorial correctly', () => { | |||
expect(shallow(<TutorialSuggestionGithub />)).toMatchSnapshot(); | |||
}); | |||
it('renders microsoft tutorial correctly', () => { | |||
expect(shallow(<TutorialSuggestionVSTS />)).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,207 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`renders for Azure 1`] = ` | |||
<DeferredSpinner | |||
customSpinner={<Unknown />} | |||
loading={false} | |||
timeout={100} | |||
> | |||
<TutorialSuggestionVSTS /> | |||
</DeferredSpinner> | |||
`; | |||
exports[`renders for BitBucket 1`] = ` | |||
<DeferredSpinner | |||
customSpinner={<Unknown />} | |||
loading={false} | |||
timeout={100} | |||
> | |||
<TutorialSuggestionBitbucket /> | |||
<TokenStep | |||
currentUser={ | |||
Object { | |||
"externalProvider": "github", | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
finished={false} | |||
initialTokenName="Analyze \\"MyProject\\"" | |||
onContinue={[Function]} | |||
onOpen={[Function]} | |||
open={true} | |||
stepNumber={1} | |||
/> | |||
<ProjectAnalysisStep | |||
component={ | |||
Object { | |||
"alm": Object { | |||
"key": "bitbucket", | |||
"url": "https://bitbucket.com/luke/lightsaber", | |||
}, | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
"name": "MyProject", | |||
"organization": "foo", | |||
"qualifier": "TRK", | |||
"qualityGate": Object { | |||
"isDefault": true, | |||
"key": "30", | |||
"name": "Sonar way", | |||
}, | |||
"qualityProfiles": Array [ | |||
Object { | |||
"deleted": false, | |||
"key": "my-qp", | |||
"language": "ts", | |||
"name": "Sonar way", | |||
}, | |||
], | |||
"tags": Array [], | |||
} | |||
} | |||
displayRowLayout={true} | |||
open={false} | |||
stepNumber={2} | |||
/> | |||
</DeferredSpinner> | |||
`; | |||
exports[`renders for GitHub 1`] = ` | |||
<DeferredSpinner | |||
customSpinner={<Unknown />} | |||
loading={false} | |||
timeout={100} | |||
> | |||
<div | |||
className="page-analysis-container page-analysis-container-sonarcloud" | |||
> | |||
<div | |||
className="page-analysis big-spacer-top big-spacer-bottom huge-spacer-left huge-spacer-right" | |||
> | |||
<div | |||
className="page-header big-spacer-bottom" | |||
> | |||
<h1 | |||
className="big-spacer-bottom" | |||
> | |||
onboarding.project_analysis.header | |||
</h1> | |||
<p> | |||
<InstanceMessage | |||
message="onboarding.project_analysis.description" | |||
/> | |||
</p> | |||
</div> | |||
<div | |||
className="mode-type mode-type-autoscan huge-spacer-top huge-spacer-bottom" | |||
> | |||
<div | |||
className="icon" | |||
> | |||
<div | |||
className="badge badge-new" | |||
> | |||
BETA | |||
</div> | |||
</div> | |||
<p> | |||
SonarCloud Automatic Analysis | |||
</p> | |||
<button | |||
className="button big-spacer-top big-spacer-bottom" | |||
onClick={[Function]} | |||
type="button" | |||
> | |||
projects.configure_analysis | |||
</button> | |||
</div> | |||
<div | |||
className="analysis-modes" | |||
> | |||
<div | |||
className="mode-type mode-type-travis" | |||
key="travis" | |||
> | |||
<div | |||
className="icon" | |||
/> | |||
<div | |||
className="name" | |||
> | |||
With Travis CI | |||
</div> | |||
<button | |||
className="button big-spacer-top big-spacer-bottom" | |||
onClick={[Function]} | |||
type="button" | |||
> | |||
projects.configure_analysis | |||
</button> | |||
</div> | |||
<div | |||
className="mode-type mode-type-other" | |||
key="other" | |||
> | |||
<div | |||
className="icon" | |||
/> | |||
<div | |||
className="name" | |||
> | |||
With other CI tools | |||
</div> | |||
<button | |||
className="button big-spacer-top big-spacer-bottom" | |||
onClick={[Function]} | |||
type="button" | |||
> | |||
projects.configure_analysis | |||
</button> | |||
</div> | |||
<div | |||
className="mode-type mode-type-manual" | |||
key="manual" | |||
> | |||
<div | |||
className="icon" | |||
/> | |||
<div | |||
className="name" | |||
> | |||
Manually | |||
</div> | |||
<button | |||
className="button big-spacer-top big-spacer-bottom" | |||
onClick={[Function]} | |||
type="button" | |||
> | |||
projects.configure_analysis | |||
</button> | |||
</div> | |||
</div> | |||
</div> | |||
</div> | |||
</DeferredSpinner> | |||
`; | |||
exports[`renders for a non supported component 1`] = ` | |||
<DeferredSpinner | |||
customSpinner={<Unknown />} | |||
loading={true} | |||
timeout={100} | |||
/> | |||
`; | |||
exports[`should have a spinner 1`] = ` | |||
<div | |||
className="display-flex-justify-center spinner-margin" | |||
> | |||
<i | |||
className="spinner global-loading-spinner" | |||
/> | |||
</div> | |||
`; |
@@ -1,6 +1,6 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`renders bitbucket suggestions correctly 1`] = ` | |||
exports[`renders bitbucket tutorial correctly 1`] = ` | |||
<Alert | |||
className="big-spacer-bottom" | |||
variant="info" | |||
@@ -21,7 +21,7 @@ exports[`renders bitbucket suggestions correctly 1`] = ` | |||
rel="noopener noreferrer" | |||
target="_blank" | |||
> | |||
onboarding.project_analysis.guide_to_integrate_piplines | |||
onboarding.project_analysis.guide_to_integrate_pipelines | |||
</a>, | |||
} | |||
} | |||
@@ -29,7 +29,7 @@ exports[`renders bitbucket suggestions correctly 1`] = ` | |||
</Alert> | |||
`; | |||
exports[`renders github suggestions correctly 1`] = ` | |||
exports[`renders github tutorial correctly 1`] = ` | |||
<Alert | |||
className="big-spacer-bottom" | |||
variant="info" | |||
@@ -59,7 +59,7 @@ exports[`renders github suggestions correctly 1`] = ` | |||
</Alert> | |||
`; | |||
exports[`renders vsts suggestions correctly 1`] = ` | |||
exports[`renders microsoft tutorial correctly 1`] = ` | |||
<Alert | |||
className="big-spacer-bottom" | |||
variant="info" |
@@ -0,0 +1,59 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import { isAutoScannable } from '../utils'; | |||
it('should work for supported languages', () => { | |||
expect( | |||
isAutoScannable({ | |||
JavaScript: 512636, | |||
TypeScript: 425475, | |||
HTML: 390075, | |||
CSS: 14099, | |||
Makefile: 536, | |||
Dockerfile: 319 | |||
}) | |||
).toEqual({ | |||
withAllowedLanguages: true, | |||
withNotAllowedLanguages: false | |||
}); | |||
}); | |||
it('should work for non supported languages', () => { | |||
expect( | |||
isAutoScannable({ | |||
Java: 434 | |||
}) | |||
).toEqual({ | |||
withAllowedLanguages: false, | |||
withNotAllowedLanguages: true | |||
}); | |||
}); | |||
it('should work for mixed languages', () => { | |||
expect( | |||
isAutoScannable({ | |||
JavaScript: 512636, | |||
Java: 434 | |||
}) | |||
).toEqual({ | |||
withAllowedLanguages: true, | |||
withNotAllowedLanguages: true | |||
}); | |||
}); |
@@ -0,0 +1,71 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { Alert } from '../../../../components/ui/Alert'; | |||
import DocTooltip from '../../../../components/docs/DocTooltip'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
const caveats = { | |||
default: ` | |||
No visual feedback (yet) in the UI. | |||
Only Pull Requests from the same repository are analyzed. | |||
Not supported: code coverage, import of external rule engine reports. | |||
--- | |||
[Read more](https://sonarcloud.io/documentation/autoscan/) and join [the forum](https://community.sonarsource.com/tags/c/help/sc/autoscan) to ask your questions | |||
` | |||
}; | |||
const limitedScope = { | |||
default: ` | |||
The following languages are currently supported: | |||
ABAP, Apex, CSS, Flex, Go, HTML, JS, Kotlin, PHP, Python, Ruby, Scala, Swift, TypeScript, TSQL, XML. | |||
` | |||
}; | |||
export function AutoScanAlert() { | |||
return ( | |||
<Alert className="big-spacer-top" variant="info"> | |||
<div> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.with.autoscan.alert')} | |||
id="onboarding.analysis.with.autoscan.alert" | |||
values={{ | |||
caveats: ( | |||
<> | |||
<strong>{translate('onboarding.analysis.with.autoscan.alert.caveats')}</strong>{' '} | |||
<DocTooltip doc={Promise.resolve(caveats)} /> | |||
</> | |||
), | |||
scopes: ( | |||
<> | |||
<strong>{translate('onboarding.analysis.with.autoscan.alert.scopes')}</strong>{' '} | |||
<DocTooltip doc={Promise.resolve(limitedScope)} /> | |||
</> | |||
) | |||
}} | |||
/> | |||
</div> | |||
</Alert> | |||
); | |||
} |
@@ -0,0 +1,126 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { AutoScanAlert } from './AutoScanAlert'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import { Button, ResetButtonLink } from '../../../../components/ui/buttons'; | |||
import Step from '../../components/Step'; | |||
import DropdownIcon from '../../../../components/icons-components/DropdownIcon'; | |||
import { TutorialProps } from '../utils'; | |||
export default function ConfigureWithAutoScan({ onDone }: TutorialProps) { | |||
const [showCustomizationOptions, setCustomizationOptions] = React.useState<boolean>(false); | |||
const command = `# Path to sources | |||
#sonar.sources=. | |||
#sonar.exclusions= | |||
#sonar.inclusions= | |||
# Path to tests | |||
#sonar.tests= | |||
#sonar.test.exclusions= | |||
#sonar.test.inclusions= | |||
# Source encoding | |||
#sonar.sourceEncoding=UTF-8 | |||
# Exclusions for copy-paste detection | |||
#sonar.cpd.exclusions=`; | |||
const renderForm = () => ( | |||
<div className="boxed-group-inner"> | |||
<div className="flex-columns"> | |||
<div className="flex-column-full"> | |||
<p className="spacer-bottom"> | |||
Add this file in the base directory of your default branch or on a PR. | |||
</p> | |||
<p className="spacer-bottom"> | |||
You can push an empty <code>.sonarcloud.properties</code> file, this will work fine. In | |||
this case, every file in the repository will be considered as a source file. | |||
</p> | |||
<ResetButtonLink onClick={() => setCustomizationOptions(!showCustomizationOptions)}> | |||
{showCustomizationOptions ? 'Hide customization options' : 'Show customization options'} | |||
<DropdownIcon className="little-spacer-left" turned={showCustomizationOptions} /> | |||
</ResetButtonLink> | |||
<div hidden={!showCustomizationOptions}> | |||
<p> | |||
Here are the supported optional settings for the <code>.sonarcloud.properties</code>{' '} | |||
file: | |||
</p> | |||
<CodeSnippet snippet={command} /> | |||
<p> | |||
Please refer to the{' '} | |||
<a | |||
href="https://sieg.eu.ngrok.io/documentation/autoscan/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
documentation | |||
</a>{' '} | |||
for more details. | |||
</p> | |||
</div> | |||
</div> | |||
</div> | |||
<div className="big-spacer-top"> | |||
<Button className="js-continue" onClick={onDone}> | |||
{translate('onboarding.finish')} | |||
</Button> | |||
</div> | |||
</div> | |||
); | |||
const renderResult = () => null; | |||
return ( | |||
<> | |||
<h1 className="spacer-bottom spacer-top"> | |||
{translate('onboarding.analysis.with.autoscan.title')} | |||
</h1> | |||
<p className="spacer-bottom">{translate('onboarding.analysis.with.autoscan.text')}</p> | |||
<AutoScanAlert /> | |||
<Step | |||
finished={false} | |||
onOpen={() => {}} | |||
open={true} | |||
renderForm={renderForm} | |||
renderResult={renderResult} | |||
stepNumber={1} | |||
stepTitle={ | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.with.autoscan.filename')} | |||
id="onboarding.analysis.with.autoscan.filename" | |||
values={{ | |||
filename: <code className="rule">.sonarcloud.properties</code> | |||
}} | |||
/> | |||
} | |||
/> | |||
</> | |||
); | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import ProjectAnalysisStepFromBuildTool, { | |||
ProjectAnalysisModes | |||
} from '../../components/ProjectAnalysisStepFromBuildTool'; | |||
import { TutorialProps } from '../utils'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
export default function ConfigureWithLocalScanner({ | |||
component, | |||
currentUser, | |||
onDone, | |||
setToken, | |||
token | |||
}: TutorialProps) { | |||
return ( | |||
<> | |||
<h1 className="spacer-bottom spacer-top"> | |||
{translate('onboarding.analysis.with.local.title')} | |||
</h1> | |||
<ProjectAnalysisStepFromBuildTool | |||
component={component} | |||
currentUser={currentUser} | |||
displayRowLayout={true} | |||
mode={ProjectAnalysisModes.Custom} | |||
onDone={onDone} | |||
open={true} | |||
organization={component.organization} | |||
setToken={setToken} | |||
stepNumber={1} | |||
token={token} | |||
/> | |||
</> | |||
); | |||
} |
@@ -0,0 +1,54 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import ProjectAnalysisStepFromBuildTool, { | |||
ProjectAnalysisModes | |||
} from '../../components/ProjectAnalysisStepFromBuildTool'; | |||
import { TutorialProps } from '../utils'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
export default function ConfigureWithOtherCI({ | |||
component, | |||
currentUser, | |||
onDone, | |||
setToken, | |||
token | |||
}: TutorialProps) { | |||
return ( | |||
<> | |||
<h1 className="spacer-bottom spacer-top"> | |||
{translate('onboarding.analysis.with.yourci.title')} | |||
</h1> | |||
<ProjectAnalysisStepFromBuildTool | |||
component={component} | |||
currentUser={currentUser} | |||
displayRowLayout={true} | |||
mode={ProjectAnalysisModes.CI} | |||
onDone={onDone} | |||
open={true} | |||
organization={component.organization} | |||
setToken={setToken} | |||
stepNumber={1} | |||
token={token} | |||
/> | |||
</> | |||
); | |||
} |
@@ -0,0 +1,119 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import EncryptYourTokenStep from '../steps/EncryptYourTokenStep'; | |||
import CreateSonarPropertiesStep from '../steps/CreateSonarPropertiesStep'; | |||
import EditTravisYmlStep from '../steps/EditTravisYmlStep'; | |||
import { isSonarCloud } from '../../../../helpers/system'; | |||
import { PROJECT_STEP_PROGRESS, TutorialProps } from '../utils'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import { get, save } from '../../../../helpers/storage'; | |||
enum Steps { | |||
ENCRYPT_TOKEN = 1, | |||
EDIT_TRAVIS_YML = 2, | |||
CREATE_SONAR_PROPERTIES = 3 | |||
} | |||
export default function ConfigureWithTravis({ | |||
component, | |||
currentUser, | |||
onDone, | |||
setToken, | |||
token | |||
}: TutorialProps) { | |||
const [build, setBuild] = React.useState<string | undefined>(undefined); | |||
const [step, setStep] = React.useState<Steps>(Steps.ENCRYPT_TOKEN); | |||
const [hasStepAfterTravisYml, setHasStepAfterTravilYml] = React.useState<boolean>(false); | |||
React.useEffect(() => { | |||
const value = get(PROJECT_STEP_PROGRESS, component.key); | |||
if (value) { | |||
try { | |||
const data = JSON.parse(value); | |||
setBuild(data.build); | |||
setStep(data.step); | |||
setHasStepAfterTravilYml(data.hasStepAfterTravisYml); | |||
} catch (e) { | |||
// Let's start from scratch | |||
} | |||
} | |||
}, [component.key]); | |||
const saveAndFinish = () => { | |||
save( | |||
PROJECT_STEP_PROGRESS, | |||
JSON.stringify({ | |||
build, | |||
hasStepAfterTravisYml, | |||
step | |||
}), | |||
component.key | |||
); | |||
onDone(); | |||
}; | |||
return ( | |||
<> | |||
<h1 className="spacer-bottom spacer-top"> | |||
{translate('onboarding.analysis.with.travis.title')} | |||
</h1> | |||
<EncryptYourTokenStep | |||
component={component} | |||
currentUser={currentUser} | |||
onContinue={() => setStep(Steps.EDIT_TRAVIS_YML)} | |||
onOpen={() => setStep(Steps.ENCRYPT_TOKEN)} | |||
open={step === Steps.ENCRYPT_TOKEN} | |||
setToken={setToken} | |||
stepNumber={1} | |||
token={token} | |||
/> | |||
<EditTravisYmlStep | |||
buildCallback={setBuild} | |||
buildType={build} | |||
component={component} | |||
finished={step >= 2} | |||
hasStepAfter={setHasStepAfterTravilYml} | |||
onContinue={() => | |||
hasStepAfterTravisYml ? setStep(Steps.CREATE_SONAR_PROPERTIES) : saveAndFinish() | |||
} | |||
onOpen={() => setStep(Steps.EDIT_TRAVIS_YML)} | |||
open={step === Steps.EDIT_TRAVIS_YML} | |||
organization={isSonarCloud() ? component.organization : undefined} | |||
stepNumber={2} | |||
token={token} | |||
/> | |||
{hasStepAfterTravisYml && ( | |||
<CreateSonarPropertiesStep | |||
component={component} | |||
finished={step >= 3} | |||
onContinue={saveAndFinish} | |||
onOpen={() => setStep(Steps.CREATE_SONAR_PROPERTIES)} | |||
open={step === Steps.CREATE_SONAR_PROPERTIES} | |||
stepNumber={3} | |||
/> | |||
)} | |||
</> | |||
); | |||
} |
@@ -0,0 +1,30 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import { AutoScanAlert } from '../AutoScanAlert'; | |||
it('should renders correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
function shallowRender() { | |||
return shallow(<AutoScanAlert />); | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ConfigureWithOtherCI from '../ConfigureWithOtherCI'; | |||
import { TutorialProps } from '../../utils'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../../helpers/testMocks'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<TutorialProps> = {}) { | |||
return shallow( | |||
<ConfigureWithOtherCI | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
onDone={jest.fn()} | |||
setToken={jest.fn()} | |||
token="token123" | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ConfigureWithAutoScan from '../ConfigureWithAutoScan'; | |||
import { TutorialProps } from '../../utils'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../../helpers/testMocks'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<TutorialProps> = {}) { | |||
return shallow( | |||
<ConfigureWithAutoScan | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
onDone={jest.fn()} | |||
setToken={jest.fn()} | |||
token="token123" | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,41 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ConfigureWithLocalScanner from '../ConfigureWithLocalScanner'; | |||
import { TutorialProps } from '../../utils'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../../helpers/testMocks'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<TutorialProps> = {}) { | |||
return shallow( | |||
<ConfigureWithLocalScanner | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
onDone={jest.fn()} | |||
setToken={jest.fn()} | |||
token="token123" | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,71 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ConfigureWithTravis from '../ConfigureWithTravis'; | |||
import { TutorialProps } from '../../utils'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../../helpers/testMocks'; | |||
jest.mock('../../../../../helpers/storage', () => ({ | |||
get: jest.fn().mockReturnValue( | |||
JSON.stringify({ | |||
build: 'maven', | |||
hasStepAfterTravisYml: true, | |||
step: 3 | |||
}) | |||
), | |||
save: jest.fn() | |||
})); | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should react to EditTravisYmlStep onContinue', () => { | |||
const wrapper = shallowRender(); | |||
expect(wrapper.find('EditTravisYmlStep').prop('open') as Boolean).toBeFalsy(); | |||
(wrapper.find('EncryptYourTokenStep').prop('onContinue') as Function)(); | |||
expect(wrapper.find('EditTravisYmlStep').prop('open') as Boolean).toBeTruthy(); | |||
}); | |||
it('should react to EditTravisYmlStep onOpen', () => { | |||
const wrapper = shallowRender(); | |||
(wrapper.find('EncryptYourTokenStep').prop('onContinue') as Function)(); | |||
expect(wrapper.find('EncryptYourTokenStep').prop('open') as Boolean).toBeFalsy(); | |||
(wrapper.find('EncryptYourTokenStep').prop('onOpen') as Function)(); | |||
expect(wrapper.find('EncryptYourTokenStep').prop('open') as Boolean).toBeTruthy(); | |||
}); | |||
function shallowRender(props: Partial<TutorialProps> = {}) { | |||
return shallow( | |||
<ConfigureWithTravis | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
onDone={jest.fn()} | |||
setToken={jest.fn()} | |||
token="token123" | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,37 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should renders correctly 1`] = ` | |||
<Alert | |||
className="big-spacer-top" | |||
variant="info" | |||
> | |||
<div> | |||
<FormattedMessage | |||
defaultMessage="onboarding.analysis.with.autoscan.alert" | |||
id="onboarding.analysis.with.autoscan.alert" | |||
values={ | |||
Object { | |||
"caveats": <React.Fragment> | |||
<strong> | |||
onboarding.analysis.with.autoscan.alert.caveats | |||
</strong> | |||
<DocTooltip | |||
doc={Promise {}} | |||
/> | |||
</React.Fragment>, | |||
"scopes": <React.Fragment> | |||
<strong> | |||
onboarding.analysis.with.autoscan.alert.scopes | |||
</strong> | |||
<DocTooltip | |||
doc={Promise {}} | |||
/> | |||
</React.Fragment>, | |||
} | |||
} | |||
/> | |||
</div> | |||
</Alert> | |||
`; |
@@ -0,0 +1,53 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<h1 | |||
className="spacer-bottom spacer-top" | |||
> | |||
onboarding.analysis.with.yourci.title | |||
</h1> | |||
<ProjectAnalysisStepFromBuildTool | |||
component={ | |||
Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
"name": "MyProject", | |||
"organization": "foo", | |||
"qualifier": "TRK", | |||
"qualityGate": Object { | |||
"isDefault": true, | |||
"key": "30", | |||
"name": "Sonar way", | |||
}, | |||
"qualityProfiles": Array [ | |||
Object { | |||
"deleted": false, | |||
"key": "my-qp", | |||
"language": "ts", | |||
"name": "Sonar way", | |||
}, | |||
], | |||
"tags": Array [], | |||
} | |||
} | |||
currentUser={ | |||
Object { | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
displayRowLayout={true} | |||
mode="CI" | |||
onDone={[MockFunction]} | |||
open={true} | |||
organization="foo" | |||
setToken={[MockFunction]} | |||
stepNumber={1} | |||
token="token123" | |||
/> | |||
</Fragment> | |||
`; |
@@ -0,0 +1,40 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<h1 | |||
className="spacer-bottom spacer-top" | |||
> | |||
onboarding.analysis.with.autoscan.title | |||
</h1> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
onboarding.analysis.with.autoscan.text | |||
</p> | |||
<AutoScanAlert /> | |||
<Step | |||
finished={false} | |||
onOpen={[Function]} | |||
open={true} | |||
renderForm={[Function]} | |||
renderResult={[Function]} | |||
stepNumber={1} | |||
stepTitle={ | |||
<FormattedMessage | |||
defaultMessage="onboarding.analysis.with.autoscan.filename" | |||
id="onboarding.analysis.with.autoscan.filename" | |||
values={ | |||
Object { | |||
"filename": <code | |||
className="rule" | |||
> | |||
.sonarcloud.properties | |||
</code>, | |||
} | |||
} | |||
/> | |||
} | |||
/> | |||
</Fragment> | |||
`; |
@@ -0,0 +1,53 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<h1 | |||
className="spacer-bottom spacer-top" | |||
> | |||
onboarding.analysis.with.local.title | |||
</h1> | |||
<ProjectAnalysisStepFromBuildTool | |||
component={ | |||
Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
"name": "MyProject", | |||
"organization": "foo", | |||
"qualifier": "TRK", | |||
"qualityGate": Object { | |||
"isDefault": true, | |||
"key": "30", | |||
"name": "Sonar way", | |||
}, | |||
"qualityProfiles": Array [ | |||
Object { | |||
"deleted": false, | |||
"key": "my-qp", | |||
"language": "ts", | |||
"name": "Sonar way", | |||
}, | |||
], | |||
"tags": Array [], | |||
} | |||
} | |||
currentUser={ | |||
Object { | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
displayRowLayout={true} | |||
mode="Custom" | |||
onDone={[MockFunction]} | |||
open={true} | |||
organization="foo" | |||
setToken={[MockFunction]} | |||
stepNumber={1} | |||
token="token123" | |||
/> | |||
</Fragment> | |||
`; |
@@ -0,0 +1,84 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Fragment> | |||
<h1 | |||
className="spacer-bottom spacer-top" | |||
> | |||
onboarding.analysis.with.travis.title | |||
</h1> | |||
<EncryptYourTokenStep | |||
component={ | |||
Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
"name": "MyProject", | |||
"organization": "foo", | |||
"qualifier": "TRK", | |||
"qualityGate": Object { | |||
"isDefault": true, | |||
"key": "30", | |||
"name": "Sonar way", | |||
}, | |||
"qualityProfiles": Array [ | |||
Object { | |||
"deleted": false, | |||
"key": "my-qp", | |||
"language": "ts", | |||
"name": "Sonar way", | |||
}, | |||
], | |||
"tags": Array [], | |||
} | |||
} | |||
currentUser={ | |||
Object { | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
onContinue={[Function]} | |||
onOpen={[Function]} | |||
open={true} | |||
setToken={[MockFunction]} | |||
stepNumber={1} | |||
token="token123" | |||
/> | |||
<EditTravisYmlStep | |||
buildCallback={[Function]} | |||
component={ | |||
Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
"name": "MyProject", | |||
"organization": "foo", | |||
"qualifier": "TRK", | |||
"qualityGate": Object { | |||
"isDefault": true, | |||
"key": "30", | |||
"name": "Sonar way", | |||
}, | |||
"qualityProfiles": Array [ | |||
Object { | |||
"deleted": false, | |||
"key": "my-qp", | |||
"language": "ts", | |||
"name": "Sonar way", | |||
}, | |||
], | |||
"tags": Array [], | |||
} | |||
} | |||
finished={false} | |||
hasStepAfter={[Function]} | |||
onContinue={[Function]} | |||
onOpen={[Function]} | |||
open={false} | |||
stepNumber={2} | |||
token="token123" | |||
/> | |||
</Fragment> | |||
`; |
@@ -0,0 +1,93 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import { Button } from '../../../../components/ui/buttons'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import Step from '../../components/Step'; | |||
import { StepProps } from '../../utils'; | |||
export default function CreateSonarPropertiesStep({ | |||
component, | |||
finished, | |||
onContinue, | |||
onOpen, | |||
open, | |||
stepNumber | |||
}: StepProps) { | |||
const command = `sonar.projectKey=${component ? component.key : 'my:project'} | |||
# this is the name and version displayed in the SonarCloud UI. | |||
sonar.projectName=${component ? component.name : 'My project'} | |||
sonar.projectVersion=1.0 | |||
# Path is relative to the sonar-project.properties file. Replace "\\" by "/" on Windows. | |||
# This property is optional if sonar.modules is set. | |||
sonar.sources=. | |||
# Encoding of the source code. Default is default system encoding | |||
#sonar.sourceEncoding=UTF-8`; | |||
const renderForm = () => ( | |||
<div className="boxed-group-inner"> | |||
<div className="flex-columns"> | |||
<div className="flex-column-full"> | |||
<p> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.with.travis.sonar.properties.text')} | |||
id="onboarding.analysis.with.travis.sonar.properties.text" | |||
values={{ | |||
code: <code>sonar-project.properties</code> | |||
}} | |||
/> | |||
</p> | |||
<CodeSnippet snippet={command} /> | |||
</div> | |||
</div> | |||
<div className="big-spacer-top"> | |||
<Button className="js-continue" onClick={onContinue}> | |||
{translate('onboarding.finish')} | |||
</Button> | |||
</div> | |||
</div> | |||
); | |||
const renderResult = () => null; | |||
return ( | |||
<Step | |||
finished={Boolean(finished)} | |||
onOpen={onOpen} | |||
open={open} | |||
renderForm={renderForm} | |||
renderResult={renderResult} | |||
stepNumber={stepNumber} | |||
stepTitle={ | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.with.travis.sonar.properties.title')} | |||
id="onboarding.analysis.with.travis.sonar.properties.title" | |||
values={{ | |||
filename: <code className="rule">sonar.properties</code> | |||
}} | |||
/> | |||
} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,235 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { Link } from 'react-router'; | |||
import { generateToken, getTokens, revokeToken } from '../../../../api/user-tokens'; | |||
import { getUniqueTokenName } from '../../utils'; | |||
import { translate, translateWithParameters } from '../../../../helpers/l10n'; | |||
import ConfirmModal from '../../../../components/controls/ConfirmModal'; | |||
import { Button, DeleteButton } from '../../../../components/ui/buttons'; | |||
import { RenderOptions } from '../../components/RenderOptions'; | |||
import { Alert } from '../../../../components/ui/Alert'; | |||
export enum TokenMode { | |||
use_existing_token = 'use_existing_token', | |||
generate_token = 'generate_token' | |||
} | |||
interface State { | |||
existingToken?: string; | |||
mode: TokenMode; | |||
token?: string; | |||
tokenName: string; | |||
} | |||
interface Props { | |||
component: T.Component; | |||
currentUser: T.LoggedInUser; | |||
onClose: VoidFunction; | |||
onSave: (token: string) => void; | |||
} | |||
export default class EditTokenModal extends React.PureComponent<Props, State> { | |||
mounted = false; | |||
initialTokenName = ''; | |||
state = { | |||
mode: TokenMode.use_existing_token, | |||
existingToken: '', | |||
token: '', | |||
tokenName: '' | |||
}; | |||
componentDidMount() { | |||
this.mounted = true; | |||
const { component } = this.props; | |||
this.initialTokenName = `Analyze "${component.name}"`; | |||
this.getTokensAndName(); | |||
} | |||
componentWillUnmount() { | |||
this.mounted = false; | |||
} | |||
getTokensAndName = () => { | |||
const { currentUser } = this.props; | |||
getTokens(currentUser.login).then( | |||
t => { | |||
if (this.mounted) { | |||
this.setState({ tokenName: getUniqueTokenName(t, this.initialTokenName) }); | |||
} | |||
}, | |||
() => {} | |||
); | |||
}; | |||
getNewToken = () => { | |||
const { tokenName = this.initialTokenName } = this.state; | |||
generateToken({ name: tokenName }).then( | |||
({ token }: { token: string }) => { | |||
if (this.mounted) { | |||
this.setState({ | |||
token, | |||
tokenName | |||
}); | |||
} | |||
}, | |||
() => {} | |||
); | |||
}; | |||
handleChange = (event: React.ChangeEvent<HTMLInputElement>) => { | |||
if (this.mounted) { | |||
this.setState({ | |||
tokenName: event.target.value | |||
}); | |||
} | |||
}; | |||
handleTokenRevoke = () => { | |||
const { tokenName } = this.state; | |||
if (tokenName) { | |||
revokeToken({ name: tokenName }).then( | |||
() => { | |||
if (this.mounted) { | |||
this.setState({ | |||
mode: TokenMode.use_existing_token, | |||
token: '', | |||
tokenName: '' | |||
}); | |||
} | |||
}, | |||
() => {} | |||
); | |||
} | |||
}; | |||
setExistingToken = (event: React.ChangeEvent<HTMLInputElement>) => { | |||
if (this.mounted) { | |||
this.setState({ | |||
existingToken: event.target.value | |||
}); | |||
} | |||
}; | |||
setMode = (mode: TokenMode) => { | |||
this.setState({ mode }); | |||
}; | |||
render() { | |||
const { onClose, onSave } = this.props; | |||
const { existingToken, mode, token, tokenName } = this.state; | |||
const header = translate('onboarding.token.header'); | |||
const isConfirmEnabled = | |||
(mode === TokenMode.generate_token && token) || | |||
(mode === TokenMode.use_existing_token && existingToken); | |||
const onConfirm = () => { | |||
if (mode === TokenMode.generate_token && token) { | |||
onSave(token); | |||
} else if (mode === TokenMode.use_existing_token && existingToken) { | |||
onSave(existingToken); | |||
} | |||
}; | |||
return ( | |||
<ConfirmModal | |||
confirmButtonText={translate('save')} | |||
confirmDisable={!isConfirmEnabled} | |||
header={header} | |||
onClose={onClose} | |||
onConfirm={onConfirm}> | |||
<p className="spacer-bottom"> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.token.text')} | |||
id="onboarding.token.text" | |||
values={{ | |||
link: ( | |||
<Link target="_blank" to="/account/security"> | |||
{translate('onboarding.token.text.user_account')} | |||
</Link> | |||
) | |||
}} | |||
/> | |||
</p> | |||
{token ? ( | |||
<> | |||
<span className="text-middle"> | |||
{tokenName} | |||
{': '} | |||
</span> | |||
<strong className="spacer-right text-middle">{token}</strong> | |||
<DeleteButton className="button-small text-middle" onClick={this.handleTokenRevoke} /> | |||
<Alert className="big-spacer-top" variant="warning"> | |||
{translateWithParameters('users.tokens.new_token_created', token)} | |||
</Alert> | |||
</> | |||
) : ( | |||
<> | |||
<RenderOptions | |||
checked={mode} | |||
name={'token-mode'} | |||
onCheck={this.setMode} | |||
optionLabelKey="onboarding.token" | |||
options={[TokenMode.use_existing_token, TokenMode.generate_token]} | |||
/> | |||
<div className="big-spacer-top"> | |||
{mode === TokenMode.generate_token && ( | |||
<> | |||
<input | |||
className="input-super-large spacer-right text-middle" | |||
onChange={this.handleChange} | |||
placeholder={translate('onboarding.token.generate_token.placeholder')} | |||
required={true} | |||
type="text" | |||
value={tokenName} | |||
/> | |||
<Button className="text-middle" disabled={!tokenName} onClick={this.getNewToken}> | |||
{translate('onboarding.token.generate')} | |||
</Button> | |||
</> | |||
)} | |||
{mode === TokenMode.use_existing_token && ( | |||
<input | |||
className="input-super-large spacer-right text-middle" | |||
onChange={this.setExistingToken} | |||
placeholder={translate('onboarding.token.use_existing_token.placeholder')} | |||
required={true} | |||
type="text" | |||
value={existingToken} | |||
/> | |||
)} | |||
</div> | |||
</> | |||
)} | |||
</ConfirmModal> | |||
); | |||
} | |||
} |
@@ -0,0 +1,111 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import AnalysisCommandTravis from '../../components/commands/AnalysisCommandTravis'; | |||
import { Button } from '../../../../components/ui/buttons'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import Step from '../../components/Step'; | |||
import BuildSystemForm from '../../components/BuildSystemForm'; | |||
import { StepProps } from '../../utils'; | |||
interface BuildProps { | |||
buildCallback: (build: string) => void; | |||
buildType?: string; | |||
} | |||
export default function EditTravisYmlStep({ | |||
buildCallback, | |||
buildType, | |||
component, | |||
finished, | |||
hasStepAfter, | |||
onContinue, | |||
onOpen, | |||
open, | |||
organization, | |||
stepNumber, | |||
token | |||
}: StepProps & BuildProps) { | |||
const [build, setBuild] = React.useState<string | undefined>(buildType || undefined); | |||
if (!build && buildType) { | |||
setBuild(buildType); | |||
} | |||
const isJavaBuild = build && ['gradle', 'maven'].includes(build); | |||
if (hasStepAfter && build) { | |||
hasStepAfter(!isJavaBuild); | |||
} | |||
const chooseBuild = (build: string) => { | |||
buildCallback(build); | |||
setBuild(build); | |||
}; | |||
const renderForm = () => ( | |||
<div className="boxed-group-inner"> | |||
<div className="flex-columns"> | |||
<div className="flex-column-full"> | |||
<BuildSystemForm build={build} setBuild={chooseBuild} /> | |||
{build && ( | |||
<AnalysisCommandTravis | |||
buildType={build} | |||
component={component} | |||
organization={organization} | |||
token={token} | |||
/> | |||
)} | |||
</div> | |||
</div> | |||
<div className="big-spacer-top"> | |||
{build && ( | |||
<Button className="js-continue" onClick={onContinue}> | |||
{translate(isJavaBuild ? 'onboarding.finish' : 'continue')} | |||
</Button> | |||
)} | |||
</div> | |||
</div> | |||
); | |||
const renderResult = () => null; | |||
return ( | |||
<Step | |||
finished={Boolean(finished)} | |||
onOpen={onOpen} | |||
open={open} | |||
renderForm={renderForm} | |||
renderResult={renderResult} | |||
stepNumber={stepNumber} | |||
stepTitle={ | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.travis.sonarcloud')} | |||
id="onboarding.analysis.travis.sonarcloud" | |||
values={{ | |||
filename: <code className="rule">.travis.yml</code> | |||
}} | |||
/> | |||
} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,112 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import EditTokenModal from './EditTokenModal'; | |||
import { Button, EditButton } from '../../../../components/ui/buttons'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import Step from '../../components/Step'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
export interface YourTokenProps { | |||
component: T.Component; | |||
currentUser: T.LoggedInUser; | |||
hasStepAfter?: (hasStepAfter: boolean) => void; | |||
onContinue: VoidFunction; | |||
onOpen: VoidFunction; | |||
open: boolean; | |||
organization?: string; | |||
setToken: (token: string) => void; | |||
stepNumber: number; | |||
token?: string; | |||
} | |||
export default function EncryptYourTokenStep({ | |||
component, | |||
currentUser, | |||
onContinue, | |||
onOpen, | |||
open, | |||
setToken, | |||
stepNumber, | |||
token | |||
}: YourTokenProps) { | |||
const [showModal, toggleModal] = React.useState<boolean>(false); | |||
const close = () => toggleModal(!showModal); | |||
const save = (token: string) => { | |||
setToken(token); | |||
close(); | |||
}; | |||
const command = `travis encrypt {token}`; | |||
const renderCommand = () => ( | |||
<div className="spacer-bottom"> | |||
travis encrypt {token} | |||
<EditButton className="edit-token spacer-left" onClick={() => toggleModal(true)} /> | |||
</div> | |||
); | |||
const renderForm = () => ( | |||
<div className="boxed-group-inner"> | |||
{showModal && ( | |||
<EditTokenModal | |||
component={component} | |||
currentUser={currentUser} | |||
onClose={close} | |||
onSave={save} | |||
/> | |||
)} | |||
<div className="display-flex-space-between"> | |||
<div className="display-inline-block"> | |||
<a | |||
href="https://docs.travis-ci.com/user/encryption-keys/#usage" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.analysis.with.travis.encrypt.docs.link.label')} | |||
</a> | |||
<br /> | |||
<CodeSnippet isOneLine={true} render={renderCommand} snippet={command} wrap={true} /> | |||
</div> | |||
</div> | |||
<div className="big-spacer-top"> | |||
<Button className="js-continue" onClick={onContinue}> | |||
{translate('continue')} | |||
</Button> | |||
</div> | |||
</div> | |||
); | |||
const renderResult = () => null; | |||
return ( | |||
<Step | |||
finished={true} | |||
onOpen={onOpen} | |||
open={open} | |||
renderForm={renderForm} | |||
renderResult={renderResult} | |||
stepNumber={stepNumber} | |||
stepTitle={translate('onboarding.analysis.with.travis.encrypt.title')} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import CreateSonarPropertiesStep from '../CreateSonarPropertiesStep'; | |||
import { StepProps } from '../../../utils'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<StepProps> = {}) { | |||
return shallow( | |||
<CreateSonarPropertiesStep | |||
onContinue={jest.fn()} | |||
onOpen={jest.fn()} | |||
open={true} | |||
stepNumber={1} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,132 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import EditTokenModal, { TokenMode } from '../EditTokenModal'; | |||
import { mockComponent, mockEvent, mockLoggedInUser } from '../../../../../helpers/testMocks'; | |||
import { waitAndUpdate } from '../../../../../helpers/testUtils'; | |||
import { generateToken, getTokens, revokeToken } from '../../../../../api/user-tokens'; | |||
import { getUniqueTokenName } from '../../../utils'; | |||
jest.mock('../../../../../api/user-tokens', () => ({ | |||
generateToken: jest.fn().mockResolvedValue({ | |||
name: 'baz', | |||
createdAt: '2019-01-21T08:06:00+0100', | |||
login: 'luke', | |||
token: 'token_value' | |||
}), | |||
getTokens: jest.fn().mockResolvedValue([ | |||
{ | |||
name: 'foo', | |||
createdAt: '2019-01-15T15:06:33+0100', | |||
lastConnectionDate: '2019-01-18T15:06:33+0100' | |||
}, | |||
{ name: 'bar', createdAt: '2019-01-18T15:06:33+0100' } | |||
]), | |||
revokeToken: jest.fn().mockResolvedValue(Promise.resolve()) | |||
})); | |||
jest.mock('../../../utils', () => ({ | |||
getUniqueTokenName: jest.fn().mockReturnValue('lightsaber-9000') | |||
})); | |||
beforeEach(() => { | |||
jest.clearAllMocks(); | |||
}); | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should get tokens and unique name', async () => { | |||
const wrapper = shallowRender(); | |||
const { getTokensAndName } = wrapper.instance(); | |||
getTokensAndName(); | |||
await waitAndUpdate(wrapper); | |||
expect(getTokens).toHaveBeenCalled(); | |||
expect(getUniqueTokenName).toHaveBeenCalled(); | |||
expect(wrapper.state('tokenName')).toBe('lightsaber-9000'); | |||
}); | |||
it('should get a new token', async () => { | |||
const wrapper = shallowRender(); | |||
const { getNewToken } = wrapper.instance(); | |||
getNewToken(); | |||
await waitAndUpdate(wrapper); | |||
expect(generateToken).toHaveBeenCalled(); | |||
expect(wrapper.state('token')).toBe('token_value'); | |||
}); | |||
it('should handle token revocation', async () => { | |||
const wrapper = shallowRender(); | |||
const { getTokensAndName, handleTokenRevoke } = wrapper.instance(); | |||
getTokensAndName(); | |||
await waitAndUpdate(wrapper); | |||
handleTokenRevoke(); | |||
await waitAndUpdate(wrapper); | |||
expect(revokeToken).toHaveBeenCalled(); | |||
expect(wrapper.state('token')).toBe(''); | |||
expect(wrapper.state('tokenName')).toBe(''); | |||
}); | |||
it('should handle change on user input', () => { | |||
const wrapper = shallowRender(); | |||
const instance = wrapper.instance(); | |||
instance.handleChange(mockEvent({ target: { value: 'my-token' } })); | |||
expect(wrapper.state('tokenName')).toBe('my-token'); | |||
}); | |||
it('should set existing token', () => { | |||
const wrapper = shallowRender(); | |||
const instance = wrapper.instance(); | |||
instance.setExistingToken(mockEvent({ target: { value: 'my-token' } })); | |||
expect(wrapper.state('existingToken')).toBe('my-token'); | |||
}); | |||
it('should set mode', () => { | |||
const wrapper = shallowRender(); | |||
const instance = wrapper.instance(); | |||
instance.setMode(TokenMode.generate_token); | |||
expect(wrapper.state('mode')).toBe(TokenMode.generate_token); | |||
instance.setMode(TokenMode.use_existing_token); | |||
expect(wrapper.state('mode')).toBe(TokenMode.use_existing_token); | |||
}); | |||
it('should call onSave with the token', () => {}); | |||
function shallowRender() { | |||
return shallow<EditTokenModal>( | |||
<EditTokenModal | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
onClose={jest.fn()} | |||
onSave={jest.fn()} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,49 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import EditTravisYmlStep from '../EditTravisYmlStep'; | |||
import { StepProps } from '../../../utils'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should render the form correctly', () => { | |||
expect( | |||
shallowRender() | |||
.find('Step') | |||
.prop<Function>('renderForm')() | |||
).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<StepProps> = {}) { | |||
return shallow( | |||
<EditTravisYmlStep | |||
buildCallback={jest.fn()} | |||
buildType="maven" | |||
onContinue={jest.fn()} | |||
onOpen={jest.fn()} | |||
open={true} | |||
stepNumber={1} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,43 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import EncryptYourTokenStep from '../EncryptYourTokenStep'; | |||
import { StepProps } from '../../../utils'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../../helpers/testMocks'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<StepProps> = {}) { | |||
return shallow( | |||
<EncryptYourTokenStep | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
onContinue={jest.fn()} | |||
onOpen={jest.fn()} | |||
open={true} | |||
setToken={jest.fn()} | |||
stepNumber={1} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,27 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Step | |||
finished={false} | |||
onOpen={[MockFunction]} | |||
open={true} | |||
renderForm={[Function]} | |||
renderResult={[Function]} | |||
stepNumber={1} | |||
stepTitle={ | |||
<FormattedMessage | |||
defaultMessage="onboarding.analysis.with.travis.sonar.properties.title" | |||
id="onboarding.analysis.with.travis.sonar.properties.title" | |||
values={ | |||
Object { | |||
"filename": <code | |||
className="rule" | |||
> | |||
sonar.properties | |||
</code>, | |||
} | |||
} | |||
/> | |||
} | |||
/> | |||
`; |
@@ -0,0 +1,56 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<ConfirmModal | |||
confirmButtonText="save" | |||
confirmDisable={true} | |||
header="onboarding.token.header" | |||
onClose={[MockFunction]} | |||
onConfirm={[Function]} | |||
> | |||
<p | |||
className="spacer-bottom" | |||
> | |||
<FormattedMessage | |||
defaultMessage="onboarding.token.text" | |||
id="onboarding.token.text" | |||
values={ | |||
Object { | |||
"link": <Link | |||
onlyActiveOnIndex={false} | |||
style={Object {}} | |||
target="_blank" | |||
to="/account/security" | |||
> | |||
onboarding.token.text.user_account | |||
</Link>, | |||
} | |||
} | |||
/> | |||
</p> | |||
<RenderOptions | |||
checked="use_existing_token" | |||
name="token-mode" | |||
onCheck={[Function]} | |||
optionLabelKey="onboarding.token" | |||
options={ | |||
Array [ | |||
"use_existing_token", | |||
"generate_token", | |||
] | |||
} | |||
/> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<input | |||
className="input-super-large spacer-right text-middle" | |||
onChange={[Function]} | |||
placeholder="onboarding.token.use_existing_token.placeholder" | |||
required={true} | |||
type="text" | |||
value="" | |||
/> | |||
</div> | |||
</ConfirmModal> | |||
`; |
@@ -0,0 +1,59 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Step | |||
finished={false} | |||
onOpen={[MockFunction]} | |||
open={true} | |||
renderForm={[Function]} | |||
renderResult={[Function]} | |||
stepNumber={1} | |||
stepTitle={ | |||
<FormattedMessage | |||
defaultMessage="onboarding.analysis.travis.sonarcloud" | |||
id="onboarding.analysis.travis.sonarcloud" | |||
values={ | |||
Object { | |||
"filename": <code | |||
className="rule" | |||
> | |||
.travis.yml | |||
</code>, | |||
} | |||
} | |||
/> | |||
} | |||
/> | |||
`; | |||
exports[`should render the form correctly 1`] = ` | |||
<div | |||
className="boxed-group-inner" | |||
> | |||
<div | |||
className="flex-columns" | |||
> | |||
<div | |||
className="flex-column-full" | |||
> | |||
<BuildSystemForm | |||
build="maven" | |||
setBuild={[Function]} | |||
/> | |||
<AnalysisCommandTravis | |||
buildType="maven" | |||
/> | |||
</div> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<Button | |||
className="js-continue" | |||
onClick={[MockFunction]} | |||
> | |||
onboarding.finish | |||
</Button> | |||
</div> | |||
</div> | |||
`; |
@@ -0,0 +1,13 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Step | |||
finished={true} | |||
onOpen={[MockFunction]} | |||
open={true} | |||
renderForm={[Function]} | |||
renderResult={[Function]} | |||
stepNumber={1} | |||
stepTitle="onboarding.analysis.with.travis.encrypt.title" | |||
/> | |||
`; |
@@ -0,0 +1,119 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
export const PROJECT_ONBOARDING_DONE = 'sonarcloud.project.onboarding.finished'; | |||
export const PROJECT_ONBOARDING_MODE_ID = 'sonarcloud.project.onboarding.mode.id'; | |||
export const PROJECT_STEP_PROGRESS = 'sonarcloud.project.onboarding.step.progress'; | |||
export interface AlmLanguagesStats { | |||
[k: string]: number; | |||
} | |||
export interface Alm { | |||
id: string; | |||
name: string; | |||
} | |||
export interface AnalysisMode { | |||
icon?: string; | |||
id: string; | |||
name: string; | |||
} | |||
export enum ALM_KEYS { | |||
BITBUCKET = 'BITBUCKET', | |||
GITHUB = 'GITHUB', | |||
MICROSOFT = 'MICROSOFT' | |||
} | |||
export const alms: { [k: string]: Alm } = { | |||
[ALM_KEYS.BITBUCKET]: { | |||
id: ALM_KEYS.BITBUCKET, | |||
name: 'BitBucket' | |||
}, | |||
[ALM_KEYS.GITHUB]: { | |||
id: ALM_KEYS.GITHUB, | |||
name: 'GitHub' | |||
}, | |||
[ALM_KEYS.MICROSOFT]: { | |||
id: ALM_KEYS.MICROSOFT, | |||
name: 'Microsoft' | |||
} | |||
}; | |||
export const modes: AnalysisMode[] = [ | |||
{ | |||
id: 'travis', | |||
name: 'With Travis CI' | |||
}, | |||
{ | |||
id: 'other', | |||
name: 'With other CI tools' | |||
}, | |||
{ | |||
id: 'manual', | |||
name: 'Manually' | |||
} | |||
]; | |||
export const autoScanMode: AnalysisMode = { | |||
id: 'autoscan', | |||
name: 'SonarCloud Automatic Analysis' | |||
}; | |||
export interface TutorialProps { | |||
component: T.Component; | |||
currentUser: T.LoggedInUser; | |||
onDone: VoidFunction; | |||
setToken: (token: string) => void; | |||
style?: object; | |||
token: string | undefined; | |||
} | |||
interface AutoScannableProps { | |||
[k: string]: number; | |||
} | |||
export function isAutoScannable(languages: AutoScannableProps = {}) { | |||
const allowed = [ | |||
'ABAP', | |||
'Apex', | |||
'CSS', | |||
'Flex', | |||
'Go', | |||
'HTML', | |||
'JavaScript', | |||
'Kotlin', | |||
'PHP', | |||
'Python', | |||
'Ruby', | |||
'Scala', | |||
'Swift', | |||
'TypeScript', | |||
'TSQL', | |||
'XML' | |||
]; | |||
const notAllowed = ['Java', 'C#', 'Visual Basic', 'C', 'C++', 'Objective-C']; | |||
const withAllowedLanguages = !!Object.keys(languages).find(l => allowed.includes(l)); | |||
const withNotAllowedLanguages = !!Object.keys(languages).find(l => notAllowed.includes(l)); | |||
return { withAllowedLanguages, withNotAllowedLanguages }; | |||
} |
@@ -0,0 +1,72 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { getBaseUrl } from '../../../helpers/urls'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import BackButton from '../../../components/controls/BackButton'; | |||
interface Props { | |||
setTutorialDone: (done: boolean) => void; | |||
} | |||
export default function AnalyzeTutorialDone({ setTutorialDone }: Props) { | |||
return ( | |||
<div className="page-analysis-container page-analysis-container-sonarcloud"> | |||
<BackButton | |||
onClick={() => setTutorialDone(false)} | |||
tooltip={translate('onboarding.tutorial.return_to_tutorial')}> | |||
{translate('back')} | |||
</BackButton> | |||
<div className="page-analysis page-analysis-waiting huge-spacer-top huge-spacer-bottom"> | |||
<img | |||
alt="SonarCloud" | |||
src={`${getBaseUrl()}/images/sonarcloud/analysis/Waiting-for-analysis.svg`} | |||
/> | |||
<h1 className="big-spacer-bottom huge-spacer-top"> | |||
{translate('onboarding.finished.title')} | |||
</h1> | |||
<p>{translate('onboarding.finished.text')}</p> | |||
<div className="links huge-spacer-top huge-spacer-bottom"> | |||
<h2 className="huge-spacer-bottom">{translate('onboarding.finished.links.title')}</h2> | |||
<ul> | |||
<li className="big-spacer-bottom"> | |||
<a | |||
href="https://sonarcloud.io/documentation/user-guide/quality-gates/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
What is a Quality Gate? | |||
</a> | |||
</li> | |||
<li className="big-spacer-bottom"> | |||
<a | |||
href="https://sonarcloud.io/documentation/instance-administration/quality-profiles/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
Configure your Quality Profiles | |||
</a> | |||
. | |||
</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
); | |||
} |
@@ -0,0 +1,39 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { RenderOptions } from './RenderOptions'; | |||
interface Props { | |||
build: string | undefined; | |||
setBuild: (build: string) => void; | |||
} | |||
export default function BuildSystemForm({ build, setBuild }: Props) { | |||
return ( | |||
<RenderOptions | |||
checked={build} | |||
name="build" | |||
onCheck={setBuild} | |||
optionLabelKey={'onboarding.build'} | |||
options={['maven', 'gradle', 'make', 'other']} | |||
titleLabelKey="onboarding.build" | |||
/> | |||
); | |||
} |
@@ -18,6 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { RenderOptions } from './RenderOptions'; | |||
import NewProjectForm from './NewProjectForm'; | |||
import RadioToggle from '../../../components/controls/RadioToggle'; | |||
import { translate } from '../../../helpers/l10n'; | |||
@@ -28,12 +29,29 @@ interface Props { | |||
component?: T.Component; | |||
config?: LanguageConfig; | |||
onDone: (config: LanguageConfig) => void; | |||
onReset: () => void; | |||
onReset: VoidFunction; | |||
organization?: string; | |||
} | |||
type State = LanguageConfig; | |||
export interface RenderOSProps { | |||
os: string | undefined; | |||
setOS: (os: string) => void; | |||
} | |||
export function RenderOS(props: RenderOSProps) { | |||
return ( | |||
<RenderOptions | |||
checked={props.os} | |||
name="os" | |||
onCheck={props.setOS} | |||
optionLabelKey={'onboarding.language.os'} | |||
options={['linux', 'win', 'mac']} | |||
titleLabelKey={'onboarding.language.os'} | |||
/> | |||
); | |||
} | |||
export default class LanguageForm extends React.PureComponent<Props, State> { | |||
constructor(props: Props) { | |||
super(props); | |||
@@ -76,48 +94,25 @@ export default class LanguageForm extends React.PureComponent<Props, State> { | |||
}; | |||
renderJavaBuild = () => ( | |||
<div className="big-spacer-top"> | |||
<h4 className="spacer-bottom">{translate('onboarding.language.java.build_technology')}</h4> | |||
<RadioToggle | |||
name="java-build" | |||
onCheck={this.handleJavaBuildChange} | |||
options={['maven', 'gradle'].map(build => ({ | |||
label: translate('onboarding.language.java.build_technology', build), | |||
value: build | |||
}))} | |||
value={this.state.javaBuild} | |||
/> | |||
</div> | |||
<RenderOptions | |||
checked={this.state.javaBuild} | |||
name="java-build" | |||
onCheck={this.handleJavaBuildChange} | |||
optionLabelKey="onboarding.language.java.build_technology" | |||
options={['maven', 'gradle']} | |||
titleLabelKey="onboarding.language.java.build_technology" | |||
/> | |||
); | |||
renderCFamilyCompiler = () => ( | |||
<div className="big-spacer-top"> | |||
<h4 className="spacer-bottom">{translate('onboarding.language.c-family.compiler')}</h4> | |||
<RadioToggle | |||
name="c-family-compiler" | |||
onCheck={this.handleCFamilyCompilerChange} | |||
options={['msvc', 'clang-gcc'].map(compiler => ({ | |||
label: translate('onboarding.language.c-family.compiler', compiler), | |||
value: compiler | |||
}))} | |||
value={this.state.cFamilyCompiler} | |||
/> | |||
</div> | |||
); | |||
renderOS = () => ( | |||
<div className="big-spacer-top"> | |||
<h4 className="spacer-bottom">{translate('onboarding.language.os')}</h4> | |||
<RadioToggle | |||
name="os" | |||
onCheck={this.handleOSChange} | |||
options={['linux', 'win', 'mac'].map(os => ({ | |||
label: translate('onboarding.language.os', os), | |||
value: os | |||
}))} | |||
value={this.state.os} | |||
/> | |||
</div> | |||
<RenderOptions | |||
checked={this.state.cFamilyCompiler} | |||
name="c-family-compiler" | |||
onCheck={this.handleCFamilyCompilerChange} | |||
optionLabelKey={'onboarding.language.c-family.compiler'} | |||
options={['msvc', 'clang-gcc']} | |||
titleLabelKey={'onboarding.language.c-family.compiler'} | |||
/> | |||
); | |||
renderProjectKey = () => { | |||
@@ -164,8 +159,9 @@ export default class LanguageForm extends React.PureComponent<Props, State> { | |||
</div> | |||
{language === 'java' && this.renderJavaBuild()} | |||
{language === 'c-family' && this.renderCFamilyCompiler()} | |||
{((language === 'c-family' && cFamilyCompiler === 'clang-gcc') || language === 'other') && | |||
this.renderOS()} | |||
{((language === 'c-family' && cFamilyCompiler === 'clang-gcc') || language === 'other') && ( | |||
<RenderOS os={this.state.os} setOS={this.handleOSChange} /> | |||
)} | |||
{this.renderProjectKey()} | |||
</> | |||
); |
@@ -23,7 +23,7 @@ import { DeleteButton, SubmitButton } from '../../../components/ui/buttons'; | |||
import { translate } from '../../../helpers/l10n'; | |||
interface Props { | |||
onDelete: () => void; | |||
onDelete: VoidFunction; | |||
onDone: (projectKey: string) => void; | |||
organization?: string; | |||
projectKey?: string; |
@@ -28,7 +28,7 @@ interface Props { | |||
component?: T.Component; | |||
displayRowLayout?: boolean; | |||
onFinish?: (projectKey?: string) => void; | |||
onReset?: () => void; | |||
onReset?: VoidFunction; | |||
open: boolean; | |||
organization?: string; | |||
stepNumber: number; | |||
@@ -39,17 +39,17 @@ interface State { | |||
config?: LanguageConfig; | |||
} | |||
export function getProjectKey(config?: LanguageConfig, component?: T.Component) { | |||
return (component && component.key) || (config && config.projectKey); | |||
} | |||
export default class ProjectAnalysisStep extends React.PureComponent<Props, State> { | |||
state: State = {}; | |||
getProjectKey = ({ config } = this.state, { component } = this.props) => { | |||
return (component && component.key) || (config && config.projectKey); | |||
}; | |||
handleLanguageSelect = (config: LanguageConfig) => { | |||
this.setState({ config }); | |||
if (this.props.onFinish) { | |||
const projectKey = config.language !== 'java' ? this.getProjectKey({ config }) : undefined; | |||
const projectKey = config.language !== 'java' ? getProjectKey(config) : undefined; | |||
this.props.onFinish(projectKey); | |||
} | |||
}; |
@@ -0,0 +1,148 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import Step from './Step'; | |||
import BuildSystemForm from './BuildSystemForm'; | |||
import AnalysisCommandCustom from './commands/AnalysisCommandCustom'; | |||
import AnalysisCommandOtherCI from './commands/AnalysisCommandOtherCI'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { get, save } from '../../../helpers/storage'; | |||
import { PROJECT_STEP_PROGRESS } from '../analyzeProject/utils'; | |||
export enum ProjectAnalysisModes { | |||
CI = 'CI', | |||
Custom = 'Custom' | |||
} | |||
export interface Props { | |||
component: T.Component; | |||
currentUser: T.LoggedInUser; | |||
displayRowLayout?: boolean; | |||
mode: ProjectAnalysisModes; | |||
onDone: VoidFunction; | |||
onReset?: VoidFunction; | |||
open: boolean; | |||
organization?: string; | |||
setToken: (token: string) => void; | |||
stepNumber: number; | |||
token?: string; | |||
} | |||
export default function ProjectAnalysisStepFromBuildTool({ | |||
component, | |||
currentUser, | |||
displayRowLayout, | |||
mode, | |||
onDone, | |||
open, | |||
organization, | |||
setToken, | |||
stepNumber, | |||
token | |||
}: Props) { | |||
const [build, setBuild] = React.useState<string | undefined>(undefined); | |||
const [os, setOS] = React.useState<string | undefined>(undefined); | |||
React.useEffect(() => { | |||
const value = get(PROJECT_STEP_PROGRESS, component.key); | |||
if (value) { | |||
try { | |||
const data = JSON.parse(value); | |||
setBuild(data.build); | |||
setOS(data.os); | |||
} catch (e) { | |||
// Let's start from scratch | |||
} | |||
} | |||
}, [component.key]); | |||
const saveAndFinish = (data: object) => { | |||
save( | |||
PROJECT_STEP_PROGRESS, | |||
JSON.stringify({ | |||
...data, | |||
build | |||
}), | |||
component.key | |||
); | |||
onDone(); | |||
}; | |||
const renderForm = () => { | |||
const languageComponent = <BuildSystemForm build={build} setBuild={setBuild} />; | |||
let AnalysisComponent = null; | |||
if (mode === ProjectAnalysisModes.Custom) { | |||
AnalysisComponent = AnalysisCommandCustom; | |||
} else if (mode === ProjectAnalysisModes.CI) { | |||
AnalysisComponent = AnalysisCommandOtherCI; | |||
} | |||
if (displayRowLayout) { | |||
return ( | |||
<div className="boxed-group-inner"> | |||
<div className="display-flex-column"> | |||
{languageComponent} | |||
{AnalysisComponent && ( | |||
<div className="huge-spacer-top"> | |||
<AnalysisComponent | |||
buildType={build} | |||
component={component} | |||
currentUser={currentUser} | |||
onDone={saveAndFinish} | |||
organization={organization} | |||
os={os} | |||
setToken={setToken} | |||
small={true} | |||
token={token} | |||
/> | |||
</div> | |||
)} | |||
</div> | |||
</div> | |||
); | |||
} | |||
return ( | |||
<div className="boxed-group-inner"> | |||
<div className="flex-columns"> | |||
<div className="flex-column flex-column-half bordered-right">{languageComponent}</div> | |||
<div className="flex-column flex-column-half">{AnalysisComponent}</div> | |||
</div> | |||
</div> | |||
); | |||
}; | |||
const renderResult = () => null; | |||
return ( | |||
<Step | |||
finished={false} | |||
onOpen={() => {}} | |||
open={open} | |||
renderForm={renderForm} | |||
renderResult={renderResult} | |||
stepNumber={stepNumber} | |||
stepTitle={translate('onboarding.analysis.header')} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,55 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import RadioToggle from '../../../components/controls/RadioToggle'; | |||
interface RenderOptionsProps { | |||
checked: string | undefined; | |||
name: string; | |||
onCheck: (checked: string) => void; | |||
optionLabelKey: string; | |||
options: string[]; | |||
titleLabelKey?: string; | |||
} | |||
export function RenderOptions({ | |||
checked, | |||
onCheck, | |||
optionLabelKey, | |||
options, | |||
titleLabelKey | |||
}: RenderOptionsProps) { | |||
return ( | |||
<div className="big-spacer-top"> | |||
{titleLabelKey && <h4 className="spacer-bottom">{translate(titleLabelKey)}</h4>} | |||
<RadioToggle | |||
name={name} | |||
onCheck={onCheck} | |||
options={options.map(build => ({ | |||
label: translate(optionLabelKey, build), | |||
value: build | |||
}))} | |||
value={checked} | |||
/> | |||
</div> | |||
); | |||
} |
@@ -22,8 +22,8 @@ import * as React from 'react'; | |||
import * as classNames from 'classnames'; | |||
interface Props { | |||
finished: boolean; | |||
onOpen: () => void; | |||
finished?: boolean; | |||
onOpen: VoidFunction; | |||
open: boolean; | |||
renderForm: () => React.ReactNode; | |||
renderResult: () => React.ReactNode; |
@@ -27,14 +27,15 @@ import AlertSuccessIcon from '../../../components/icons-components/AlertSuccessI | |||
import { DeleteButton, SubmitButton, Button } from '../../../components/ui/buttons'; | |||
import { getTokens, generateToken, revokeToken } from '../../../api/user-tokens'; | |||
import { translate } from '../../../helpers/l10n'; | |||
import { getUniqueTokenName } from '../utils'; | |||
interface Props { | |||
currentUser: { login: string }; | |||
currentUser: Pick<T.LoggedInUser, 'login'>; | |||
finished: boolean; | |||
initialTokenName?: string; | |||
open: boolean; | |||
onContinue: (token: string) => void; | |||
onOpen: () => void; | |||
onOpen: VoidFunction; | |||
stepNumber: number; | |||
} | |||
@@ -70,7 +71,7 @@ export default class TokenStep extends React.PureComponent<Props, State> { | |||
this.props.initialTokenName !== undefined && | |||
this.props.initialTokenName === this.state.tokenName | |||
) { | |||
this.setState({ tokenName: this.getUniqueTokenName(tokens) }); | |||
this.setState({ tokenName: getUniqueTokenName(tokens) }); | |||
} | |||
} | |||
}, | |||
@@ -85,21 +86,6 @@ export default class TokenStep extends React.PureComponent<Props, State> { | |||
getToken = () => | |||
this.state.selection === 'generate' ? this.state.token : this.state.existingToken; | |||
getUniqueTokenName = (tokens: T.UserToken[]) => { | |||
const { initialTokenName = '' } = this.props; | |||
const hasToken = (name: string) => tokens.find(token => token.name === name) !== undefined; | |||
if (!hasToken(initialTokenName)) { | |||
return initialTokenName; | |||
} | |||
let i = 1; | |||
while (hasToken(`${initialTokenName} ${i}`)) { | |||
i++; | |||
} | |||
return `${initialTokenName} ${i}`; | |||
}; | |||
canContinue = () => { | |||
const { existingToken, selection, token } = this.state; | |||
const validExistingToken = existingToken.match(/^[a-z0-9]+$/) != null; |
@@ -0,0 +1,26 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import AnalyzeTutorialDone from '../AnalyzeTutorialDone'; | |||
it('should render correctly', () => { | |||
expect(shallow(<AnalyzeTutorialDone setTutorialDone={jest.fn()} />)).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,28 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import BuildSystemForm from '../BuildSystemForm'; | |||
it('should render correctly', () => { | |||
const build = 'maven'; | |||
const setBuild = jest.fn(); | |||
expect(shallow(<BuildSystemForm build={build} setBuild={setBuild} />)).toMatchSnapshot(); | |||
}); |
@@ -35,22 +35,6 @@ it('selects java', () => { | |||
(wrapper.find('RadioToggle').prop('onCheck') as Function)('java'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper | |||
.find('RadioToggle') | |||
.at(1) | |||
.prop('onCheck') as Function)('maven'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
expect(onDone).lastCalledWith({ language: 'java', javaBuild: 'maven' }); | |||
(wrapper | |||
.find('RadioToggle') | |||
.at(1) | |||
.prop('onCheck') as Function)('gradle'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
expect(onDone).lastCalledWith({ language: 'java', javaBuild: 'gradle' }); | |||
}); | |||
it('selects c#', () => { | |||
@@ -73,42 +57,6 @@ it('selects c-family', () => { | |||
(wrapper.find('RadioToggle').prop('onCheck') as Function)('c-family'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper | |||
.find('RadioToggle') | |||
.at(1) | |||
.prop('onCheck') as Function)('msvc'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo'); | |||
expect(onDone).lastCalledWith({ | |||
language: 'c-family', | |||
cFamilyCompiler: 'msvc', | |||
projectKey: 'project-foo' | |||
}); | |||
(wrapper | |||
.find('RadioToggle') | |||
.at(1) | |||
.prop('onCheck') as Function)('clang-gcc'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper | |||
.find('RadioToggle') | |||
.at(2) | |||
.prop('onCheck') as Function)('linux'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo'); | |||
expect(onDone).lastCalledWith({ | |||
language: 'c-family', | |||
cFamilyCompiler: 'clang-gcc', | |||
os: 'linux', | |||
projectKey: 'project-foo' | |||
}); | |||
}); | |||
it('selects other', () => { | |||
@@ -118,14 +66,4 @@ it('selects other', () => { | |||
(wrapper.find('RadioToggle').prop('onCheck') as Function)('other'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper | |||
.find('RadioToggle') | |||
.at(1) | |||
.prop('onCheck') as Function)('mac'); | |||
wrapper.update(); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper.find('NewProjectForm').prop('onDone') as Function)('project-foo'); | |||
expect(onDone).lastCalledWith({ language: 'other', os: 'mac', projectKey: 'project-foo' }); | |||
}); |
@@ -18,7 +18,7 @@ | |||
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. | |||
*/ | |||
import * as React from 'react'; | |||
import { mount } from 'enzyme'; | |||
import { shallow } from 'enzyme'; | |||
import NewProjectForm from '../NewProjectForm'; | |||
import { change, submit, waitAndUpdate } from '../../../../helpers/testUtils'; | |||
@@ -31,7 +31,7 @@ jest.mock('../../../../components/icons-components/DeleteIcon'); | |||
it('creates new project', async () => { | |||
const onDone = jest.fn(); | |||
const wrapper = mount(<NewProjectForm onDelete={jest.fn()} onDone={onDone} />); | |||
const wrapper = shallow(<NewProjectForm onDelete={jest.fn()} onDone={onDone} />); | |||
expect(wrapper).toMatchSnapshot(); | |||
change(wrapper.find('input'), 'foo'); | |||
submit(wrapper.find('form')); | |||
@@ -43,7 +43,7 @@ it('creates new project', async () => { | |||
it('deletes project', async () => { | |||
const onDelete = jest.fn(); | |||
const wrapper = mount(<NewProjectForm onDelete={onDelete} onDone={jest.fn()} />); | |||
const wrapper = shallow(<NewProjectForm onDelete={onDelete} onDone={jest.fn()} />); | |||
wrapper.setState({ done: true, loading: false, projectKey: 'foo' }); | |||
expect(wrapper).toMatchSnapshot(); | |||
(wrapper.find('DeleteButton').prop('onClick') as Function)(); |
@@ -0,0 +1,31 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import { mockComponent } from '../../../../helpers/testMocks'; | |||
import ProjectAnalysisStep from '../ProjectAnalysisStep'; | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
function shallowRender() { | |||
return shallow(<ProjectAnalysisStep component={mockComponent()} open={true} stepNumber={1} />); | |||
} |
@@ -0,0 +1,69 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ProjectAnalysisStepFromBuildTool, { | |||
ProjectAnalysisModes, | |||
Props | |||
} from '../ProjectAnalysisStepFromBuildTool'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../helpers/testMocks'; | |||
jest.mock('../../../../helpers/storage', () => ({ | |||
get: jest.fn().mockReturnValue( | |||
JSON.stringify({ | |||
build: 'maven', | |||
os: 'linux' | |||
}) | |||
), | |||
save: jest.fn() | |||
})); | |||
it('should render correctly', () => { | |||
expect(shallowRender()).toMatchSnapshot(); | |||
}); | |||
it('should render the form correctly', () => { | |||
expect( | |||
shallowRender({ mode: ProjectAnalysisModes.CI }) | |||
.find('Step') | |||
.prop<Function>('renderForm')() | |||
).toMatchSnapshot(); | |||
expect( | |||
shallowRender({ displayRowLayout: true }) | |||
.find('Step') | |||
.prop<Function>('renderForm')() | |||
).toMatchSnapshot(); | |||
}); | |||
function shallowRender(props: Partial<Props> = {}) { | |||
return shallow( | |||
<ProjectAnalysisStepFromBuildTool | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
mode={ProjectAnalysisModes.Custom} | |||
onDone={jest.fn()} | |||
open={true} | |||
setToken={jest.fn()} | |||
stepNumber={1} | |||
{...props} | |||
/> | |||
); | |||
} |
@@ -28,7 +28,7 @@ jest.mock('../../../../api/user-tokens', () => ({ | |||
revokeToken: () => Promise.resolve() | |||
})); | |||
const currentUser = { login: 'user' }; | |||
const currentUser: Pick<T.LoggedInUser, 'login'> = { login: 'user' }; | |||
it('generates token', async () => { | |||
const wrapper = shallow( |
@@ -0,0 +1,64 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<div | |||
className="page-analysis-container page-analysis-container-sonarcloud" | |||
> | |||
<BackButton | |||
onClick={[Function]} | |||
tooltip="onboarding.tutorial.return_to_tutorial" | |||
> | |||
back | |||
</BackButton> | |||
<div | |||
className="page-analysis page-analysis-waiting huge-spacer-top huge-spacer-bottom" | |||
> | |||
<img | |||
alt="SonarCloud" | |||
src="/images/sonarcloud/analysis/Waiting-for-analysis.svg" | |||
/> | |||
<h1 | |||
className="big-spacer-bottom huge-spacer-top" | |||
> | |||
onboarding.finished.title | |||
</h1> | |||
<p> | |||
onboarding.finished.text | |||
</p> | |||
<div | |||
className="links huge-spacer-top huge-spacer-bottom" | |||
> | |||
<h2 | |||
className="huge-spacer-bottom" | |||
> | |||
onboarding.finished.links.title | |||
</h2> | |||
<ul> | |||
<li | |||
className="big-spacer-bottom" | |||
> | |||
<a | |||
href="https://sonarcloud.io/documentation/user-guide/quality-gates/" | |||
rel="noopener noreferrer" | |||
target="_blank" | |||
> | |||
What is a Quality Gate? | |||
</a> | |||
</li> | |||
<li | |||
className="big-spacer-bottom" | |||
> | |||
<a | |||
href="https://sonarcloud.io/documentation/instance-administration/quality-profiles/" | |||
rel="noopener noreferrer" | |||
target="_blank" | |||
> | |||
Configure your Quality Profiles | |||
</a> | |||
. | |||
</li> | |||
</ul> | |||
</div> | |||
</div> | |||
</div> | |||
`; |
@@ -0,0 +1,19 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<RenderOptions | |||
checked="maven" | |||
name="build" | |||
onCheck={[MockFunction]} | |||
optionLabelKey="onboarding.build" | |||
options={ | |||
Array [ | |||
"maven", | |||
"gradle", | |||
"make", | |||
"other", | |||
] | |||
} | |||
titleLabelKey="onboarding.build" | |||
/> | |||
`; |
@@ -73,298 +73,17 @@ exports[`selects c-family 1`] = ` | |||
value="c-family" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.c-family.compiler | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="c-family-compiler" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.msvc", | |||
"value": "msvc", | |||
}, | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.clang-gcc", | |||
"value": "clang-gcc", | |||
}, | |||
] | |||
} | |||
value={null} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`selects c-family 2`] = ` | |||
<Fragment> | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="language" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java", | |||
"value": "java", | |||
}, | |||
Object { | |||
"label": "onboarding.language.dotnet", | |||
"value": "dotnet", | |||
}, | |||
Object { | |||
"label": "onboarding.language.c-family", | |||
"value": "c-family", | |||
}, | |||
Object { | |||
"label": "onboarding.language.other", | |||
"value": "other", | |||
}, | |||
] | |||
} | |||
value="c-family" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.c-family.compiler | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="c-family-compiler" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.msvc", | |||
"value": "msvc", | |||
}, | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.clang-gcc", | |||
"value": "clang-gcc", | |||
}, | |||
] | |||
} | |||
value="msvc" | |||
/> | |||
</div> | |||
<NewProjectForm | |||
onDelete={[Function]} | |||
onDone={[Function]} | |||
/> | |||
</Fragment> | |||
`; | |||
exports[`selects c-family 3`] = ` | |||
<Fragment> | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="language" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java", | |||
"value": "java", | |||
}, | |||
Object { | |||
"label": "onboarding.language.dotnet", | |||
"value": "dotnet", | |||
}, | |||
Object { | |||
"label": "onboarding.language.c-family", | |||
"value": "c-family", | |||
}, | |||
Object { | |||
"label": "onboarding.language.other", | |||
"value": "other", | |||
}, | |||
] | |||
} | |||
value="c-family" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.c-family.compiler | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="c-family-compiler" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.msvc", | |||
"value": "msvc", | |||
}, | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.clang-gcc", | |||
"value": "clang-gcc", | |||
}, | |||
] | |||
} | |||
value="clang-gcc" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.os | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="os" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.os.linux", | |||
"value": "linux", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.win", | |||
"value": "win", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.mac", | |||
"value": "mac", | |||
}, | |||
] | |||
} | |||
value={null} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`selects c-family 4`] = ` | |||
<Fragment> | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="language" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java", | |||
"value": "java", | |||
}, | |||
Object { | |||
"label": "onboarding.language.dotnet", | |||
"value": "dotnet", | |||
}, | |||
Object { | |||
"label": "onboarding.language.c-family", | |||
"value": "c-family", | |||
}, | |||
Object { | |||
"label": "onboarding.language.other", | |||
"value": "other", | |||
}, | |||
] | |||
} | |||
value="c-family" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.c-family.compiler | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="c-family-compiler" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.msvc", | |||
"value": "msvc", | |||
}, | |||
Object { | |||
"label": "onboarding.language.c-family.compiler.clang-gcc", | |||
"value": "clang-gcc", | |||
}, | |||
] | |||
} | |||
value="clang-gcc" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.os | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="os" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.os.linux", | |||
"value": "linux", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.win", | |||
"value": "win", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.mac", | |||
"value": "mac", | |||
}, | |||
] | |||
} | |||
value="linux" | |||
/> | |||
</div> | |||
<NewProjectForm | |||
onDelete={[Function]} | |||
onDone={[Function]} | |||
projectKey="project-foo" | |||
<RenderOptions | |||
name="c-family-compiler" | |||
onCheck={[Function]} | |||
optionLabelKey="onboarding.language.c-family.compiler" | |||
options={ | |||
Array [ | |||
"msvc", | |||
"clang-gcc", | |||
] | |||
} | |||
titleLabelKey="onboarding.language.c-family.compiler" | |||
/> | |||
</Fragment> | |||
`; | |||
@@ -400,155 +119,18 @@ exports[`selects java 1`] = ` | |||
value="java" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.java.build_technology | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="java-build" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java.build_technology.maven", | |||
"value": "maven", | |||
}, | |||
Object { | |||
"label": "onboarding.language.java.build_technology.gradle", | |||
"value": "gradle", | |||
}, | |||
] | |||
} | |||
value={null} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`selects java 2`] = ` | |||
<Fragment> | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="language" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java", | |||
"value": "java", | |||
}, | |||
Object { | |||
"label": "onboarding.language.dotnet", | |||
"value": "dotnet", | |||
}, | |||
Object { | |||
"label": "onboarding.language.other", | |||
"value": "other", | |||
}, | |||
] | |||
} | |||
value="java" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.java.build_technology | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="java-build" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java.build_technology.maven", | |||
"value": "maven", | |||
}, | |||
Object { | |||
"label": "onboarding.language.java.build_technology.gradle", | |||
"value": "gradle", | |||
}, | |||
] | |||
} | |||
value="maven" | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`selects java 3`] = ` | |||
<Fragment> | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="language" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java", | |||
"value": "java", | |||
}, | |||
Object { | |||
"label": "onboarding.language.dotnet", | |||
"value": "dotnet", | |||
}, | |||
Object { | |||
"label": "onboarding.language.other", | |||
"value": "other", | |||
}, | |||
] | |||
} | |||
value="java" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.java.build_technology | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="java-build" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java.build_technology.maven", | |||
"value": "maven", | |||
}, | |||
Object { | |||
"label": "onboarding.language.java.build_technology.gradle", | |||
"value": "gradle", | |||
}, | |||
] | |||
} | |||
value="gradle" | |||
/> | |||
</div> | |||
<RenderOptions | |||
name="java-build" | |||
onCheck={[Function]} | |||
optionLabelKey="onboarding.language.java.build_technology" | |||
options={ | |||
Array [ | |||
"maven", | |||
"gradle", | |||
] | |||
} | |||
titleLabelKey="onboarding.language.java.build_technology" | |||
/> | |||
</Fragment> | |||
`; | |||
@@ -583,105 +165,8 @@ exports[`selects other 1`] = ` | |||
value="other" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.os | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="os" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.os.linux", | |||
"value": "linux", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.win", | |||
"value": "win", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.mac", | |||
"value": "mac", | |||
}, | |||
] | |||
} | |||
value={null} | |||
/> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`selects other 2`] = ` | |||
<Fragment> | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="language" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.java", | |||
"value": "java", | |||
}, | |||
Object { | |||
"label": "onboarding.language.dotnet", | |||
"value": "dotnet", | |||
}, | |||
Object { | |||
"label": "onboarding.language.other", | |||
"value": "other", | |||
}, | |||
] | |||
} | |||
value="other" | |||
/> | |||
</div> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.os | |||
</h4> | |||
<RadioToggle | |||
disabled={false} | |||
name="os" | |||
onCheck={[Function]} | |||
options={ | |||
Array [ | |||
Object { | |||
"label": "onboarding.language.os.linux", | |||
"value": "linux", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.win", | |||
"value": "win", | |||
}, | |||
Object { | |||
"label": "onboarding.language.os.mac", | |||
"value": "mac", | |||
}, | |||
] | |||
} | |||
value="mac" | |||
/> | |||
</div> | |||
<NewProjectForm | |||
onDelete={[Function]} | |||
onDone={[Function]} | |||
<RenderOS | |||
setOS={[Function]} | |||
/> | |||
</Fragment> | |||
`; |
@@ -1,321 +1,177 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`creates new project 1`] = ` | |||
<NewProjectForm | |||
onDelete={[MockFunction]} | |||
onDone={[MockFunction]} | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<div | |||
className="big-spacer-top" | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
onboarding.language.project_key | |||
</h4> | |||
<form | |||
onSubmit={[Function]} | |||
> | |||
<input | |||
autoFocus={true} | |||
className="input-large spacer-right text-middle" | |||
maxLength={400} | |||
minLength={1} | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="" | |||
/> | |||
<SubmitButton | |||
className="text-middle" | |||
disabled={true} | |||
> | |||
onboarding.language.project_key | |||
</h4> | |||
<form | |||
onSubmit={[Function]} | |||
Done | |||
</SubmitButton> | |||
<div | |||
className="note spacer-top abs-width-300" | |||
> | |||
<input | |||
autoFocus={true} | |||
className="input-large spacer-right text-middle" | |||
maxLength={400} | |||
minLength={1} | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="" | |||
/> | |||
<SubmitButton | |||
className="text-middle" | |||
disabled={true} | |||
> | |||
<Button | |||
className="text-middle" | |||
disabled={true} | |||
preventDefault={false} | |||
type="submit" | |||
> | |||
<button | |||
className="button text-middle" | |||
disabled={true} | |||
onClick={[Function]} | |||
type="submit" | |||
> | |||
Done | |||
</button> | |||
</Button> | |||
</SubmitButton> | |||
<div | |||
className="note spacer-top abs-width-300" | |||
> | |||
onboarding.project_key_requirement | |||
</div> | |||
</form> | |||
</div> | |||
</NewProjectForm> | |||
onboarding.project_key_requirement | |||
</div> | |||
</form> | |||
</div> | |||
`; | |||
exports[`creates new project 2`] = ` | |||
<NewProjectForm | |||
onDelete={[MockFunction]} | |||
onDone={[MockFunction]} | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<div | |||
className="big-spacer-top" | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.language.project_key | |||
</h4> | |||
<form | |||
onSubmit={[Function]} | |||
onboarding.language.project_key | |||
</h4> | |||
<form | |||
onSubmit={[Function]} | |||
> | |||
<input | |||
autoFocus={true} | |||
className="input-large spacer-right text-middle" | |||
maxLength={400} | |||
minLength={1} | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="foo" | |||
/> | |||
<i | |||
className="spinner text-middle" | |||
/> | |||
<div | |||
className="note spacer-top abs-width-300" | |||
> | |||
<input | |||
autoFocus={true} | |||
className="input-large spacer-right text-middle" | |||
maxLength={400} | |||
minLength={1} | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="foo" | |||
/> | |||
<i | |||
className="spinner text-middle" | |||
/> | |||
<div | |||
className="note spacer-top abs-width-300" | |||
> | |||
onboarding.project_key_requirement | |||
</div> | |||
</form> | |||
</div> | |||
</NewProjectForm> | |||
onboarding.project_key_requirement | |||
</div> | |||
</form> | |||
</div> | |||
`; | |||
exports[`creates new project 3`] = ` | |||
<NewProjectForm | |||
onDelete={[MockFunction]} | |||
onDone={ | |||
[MockFunction] { | |||
"calls": Array [ | |||
Array [ | |||
"foo", | |||
], | |||
], | |||
"results": Array [ | |||
Object { | |||
"type": "return", | |||
"value": undefined, | |||
}, | |||
], | |||
} | |||
} | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<div | |||
className="big-spacer-top" | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
onboarding.language.project_key | |||
</h4> | |||
<div> | |||
<span | |||
className="spacer-right text-middle" | |||
> | |||
onboarding.language.project_key | |||
</h4> | |||
<div> | |||
<span | |||
className="spacer-right text-middle" | |||
> | |||
foo | |||
</span> | |||
<DeleteButton | |||
className="button-small text-middle" | |||
onClick={[Function]} | |||
> | |||
<ButtonIcon | |||
className="button-small text-middle" | |||
color="#d4333f" | |||
onClick={[Function]} | |||
> | |||
<Button | |||
className="button-small text-middle button-icon" | |||
onClick={[Function]} | |||
stopPropagation={true} | |||
style={ | |||
Object { | |||
"color": "#d4333f", | |||
} | |||
} | |||
> | |||
<button | |||
className="button button-small text-middle button-icon" | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"color": "#d4333f", | |||
} | |||
} | |||
type="button" | |||
> | |||
<MOCKDeleteIcon /> | |||
</button> | |||
</Button> | |||
</ButtonIcon> | |||
</DeleteButton> | |||
</div> | |||
foo | |||
</span> | |||
<DeleteButton | |||
className="button-small text-middle" | |||
onClick={[Function]} | |||
/> | |||
</div> | |||
</NewProjectForm> | |||
</div> | |||
`; | |||
exports[`deletes project 1`] = ` | |||
<NewProjectForm | |||
onDelete={[MockFunction]} | |||
onDone={[MockFunction]} | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<div | |||
className="big-spacer-top" | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
onboarding.language.project_key | |||
</h4> | |||
<div> | |||
<span | |||
className="spacer-right text-middle" | |||
> | |||
onboarding.language.project_key | |||
</h4> | |||
<div> | |||
<span | |||
className="spacer-right text-middle" | |||
> | |||
foo | |||
</span> | |||
<DeleteButton | |||
className="button-small text-middle" | |||
onClick={[Function]} | |||
> | |||
<ButtonIcon | |||
className="button-small text-middle" | |||
color="#d4333f" | |||
onClick={[Function]} | |||
> | |||
<Button | |||
className="button-small text-middle button-icon" | |||
onClick={[Function]} | |||
stopPropagation={true} | |||
style={ | |||
Object { | |||
"color": "#d4333f", | |||
} | |||
} | |||
> | |||
<button | |||
className="button button-small text-middle button-icon" | |||
onClick={[Function]} | |||
style={ | |||
Object { | |||
"color": "#d4333f", | |||
} | |||
} | |||
type="button" | |||
> | |||
<MOCKDeleteIcon /> | |||
</button> | |||
</Button> | |||
</ButtonIcon> | |||
</DeleteButton> | |||
</div> | |||
foo | |||
</span> | |||
<DeleteButton | |||
className="button-small text-middle" | |||
onClick={[Function]} | |||
/> | |||
</div> | |||
</NewProjectForm> | |||
</div> | |||
`; | |||
exports[`deletes project 2`] = ` | |||
<NewProjectForm | |||
onDelete={[MockFunction]} | |||
onDone={[MockFunction]} | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<div | |||
className="big-spacer-top" | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
onboarding.language.project_key | |||
</h4> | |||
<div> | |||
<span | |||
className="spacer-right text-middle" | |||
> | |||
onboarding.language.project_key | |||
</h4> | |||
<div> | |||
<span | |||
className="spacer-right text-middle" | |||
> | |||
foo | |||
</span> | |||
<i | |||
className="spinner text-middle" | |||
/> | |||
</div> | |||
foo | |||
</span> | |||
<i | |||
className="spinner text-middle" | |||
/> | |||
</div> | |||
</NewProjectForm> | |||
</div> | |||
`; | |||
exports[`deletes project 3`] = ` | |||
<NewProjectForm | |||
onDelete={ | |||
[MockFunction] { | |||
"calls": Array [ | |||
Array [], | |||
], | |||
"results": Array [ | |||
Object { | |||
"type": "return", | |||
"value": undefined, | |||
}, | |||
], | |||
} | |||
} | |||
onDone={[MockFunction]} | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<div | |||
className="big-spacer-top" | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
<h4 | |||
className="spacer-bottom" | |||
onboarding.language.project_key | |||
</h4> | |||
<form | |||
onSubmit={[Function]} | |||
> | |||
<input | |||
autoFocus={true} | |||
className="input-large spacer-right text-middle" | |||
maxLength={400} | |||
minLength={1} | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="" | |||
/> | |||
<SubmitButton | |||
className="text-middle" | |||
disabled={true} | |||
> | |||
onboarding.language.project_key | |||
</h4> | |||
<form | |||
onSubmit={[Function]} | |||
Done | |||
</SubmitButton> | |||
<div | |||
className="note spacer-top abs-width-300" | |||
> | |||
<input | |||
autoFocus={true} | |||
className="input-large spacer-right text-middle" | |||
maxLength={400} | |||
minLength={1} | |||
onChange={[Function]} | |||
required={true} | |||
type="text" | |||
value="" | |||
/> | |||
<SubmitButton | |||
className="text-middle" | |||
disabled={true} | |||
> | |||
<Button | |||
className="text-middle" | |||
disabled={true} | |||
preventDefault={false} | |||
type="submit" | |||
> | |||
<button | |||
className="button text-middle" | |||
disabled={true} | |||
onClick={[Function]} | |||
type="submit" | |||
> | |||
Done | |||
</button> | |||
</Button> | |||
</SubmitButton> | |||
<div | |||
className="note spacer-top abs-width-300" | |||
> | |||
onboarding.project_key_requirement | |||
</div> | |||
</form> | |||
</div> | |||
</NewProjectForm> | |||
onboarding.project_key_requirement | |||
</div> | |||
</form> | |||
</div> | |||
`; |
@@ -0,0 +1,13 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Step | |||
finished={false} | |||
onOpen={[Function]} | |||
open={true} | |||
renderForm={[Function]} | |||
renderResult={[Function]} | |||
stepNumber={1} | |||
stepTitle="onboarding.analysis.header" | |||
/> | |||
`; |
@@ -0,0 +1,91 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<Step | |||
finished={false} | |||
onOpen={[Function]} | |||
open={true} | |||
renderForm={[Function]} | |||
renderResult={[Function]} | |||
stepNumber={1} | |||
stepTitle="onboarding.analysis.header" | |||
/> | |||
`; | |||
exports[`should render the form correctly 1`] = ` | |||
<div | |||
className="boxed-group-inner" | |||
> | |||
<div | |||
className="flex-columns" | |||
> | |||
<div | |||
className="flex-column flex-column-half bordered-right" | |||
> | |||
<BuildSystemForm | |||
setBuild={[Function]} | |||
/> | |||
</div> | |||
<div | |||
className="flex-column flex-column-half" | |||
> | |||
[Function] | |||
</div> | |||
</div> | |||
</div> | |||
`; | |||
exports[`should render the form correctly 2`] = ` | |||
<div | |||
className="boxed-group-inner" | |||
> | |||
<div | |||
className="display-flex-column" | |||
> | |||
<BuildSystemForm | |||
setBuild={[Function]} | |||
/> | |||
<div | |||
className="huge-spacer-top" | |||
> | |||
<AnalysisCommandCustom | |||
component={ | |||
Object { | |||
"breadcrumbs": Array [], | |||
"key": "my-project", | |||
"name": "MyProject", | |||
"organization": "foo", | |||
"qualifier": "TRK", | |||
"qualityGate": Object { | |||
"isDefault": true, | |||
"key": "30", | |||
"name": "Sonar way", | |||
}, | |||
"qualityProfiles": Array [ | |||
Object { | |||
"deleted": false, | |||
"key": "my-qp", | |||
"language": "ts", | |||
"name": "Sonar way", | |||
}, | |||
], | |||
"tags": Array [], | |||
} | |||
} | |||
currentUser={ | |||
Object { | |||
"groups": Array [], | |||
"isLoggedIn": true, | |||
"login": "luke", | |||
"name": "Skywalker", | |||
"scmAccounts": Array [], | |||
} | |||
} | |||
onDone={[Function]} | |||
setToken={[MockFunction]} | |||
small={true} | |||
/> | |||
</div> | |||
</div> | |||
</div> | |||
`; |
@@ -26,6 +26,7 @@ import ClangGCC from './ClangGCC'; | |||
import Other from './Other'; | |||
import { getHostUrl } from '../../../../helpers/urls'; | |||
import { LanguageConfig } from '../../utils'; | |||
import { getProjectKey } from '../ProjectAnalysisStep'; | |||
interface Props { | |||
component?: T.Component; | |||
@@ -36,10 +37,6 @@ interface Props { | |||
} | |||
export default class AnalysisCommand extends React.PureComponent<Props> { | |||
getProjectKey = ({ component, languageConfig } = this.props) => { | |||
return (component && component.key) || languageConfig.projectKey; | |||
}; | |||
renderCommandForMaven = () => { | |||
const { component, token } = this.props; | |||
if (!token) { | |||
@@ -71,8 +68,8 @@ export default class AnalysisCommand extends React.PureComponent<Props> { | |||
}; | |||
renderCommandForDotNet = () => { | |||
const { small, token } = this.props; | |||
const projectKey = this.getProjectKey(); | |||
const { component, languageConfig, small, token } = this.props; | |||
const projectKey = getProjectKey(languageConfig, component); | |||
if (!projectKey || !token) { | |||
return null; | |||
} | |||
@@ -88,8 +85,8 @@ export default class AnalysisCommand extends React.PureComponent<Props> { | |||
}; | |||
renderCommandForMSVC = () => { | |||
const { small, token } = this.props; | |||
const projectKey = this.getProjectKey(); | |||
const { component, languageConfig, small, token } = this.props; | |||
const projectKey = getProjectKey(languageConfig, component); | |||
if (!projectKey || !token) { | |||
return null; | |||
} | |||
@@ -105,8 +102,8 @@ export default class AnalysisCommand extends React.PureComponent<Props> { | |||
}; | |||
renderCommandForClangGCC = () => { | |||
const { languageConfig, small, token } = this.props; | |||
const projectKey = this.getProjectKey(); | |||
const { component, languageConfig, small, token } = this.props; | |||
const projectKey = getProjectKey(languageConfig, component); | |||
if (!languageConfig || !projectKey || !languageConfig.os || !token) { | |||
return null; | |||
} | |||
@@ -123,8 +120,8 @@ export default class AnalysisCommand extends React.PureComponent<Props> { | |||
}; | |||
renderCommandForOther = () => { | |||
const { languageConfig, token } = this.props; | |||
const projectKey = this.getProjectKey(); | |||
const { component, languageConfig, token } = this.props; | |||
const projectKey = getProjectKey(languageConfig, component); | |||
if (!languageConfig || !projectKey || !languageConfig.os || !token) { | |||
return null; | |||
} |
@@ -0,0 +1,175 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import JavaMavenCustom from './Custom/JavaMavenCustom'; | |||
import JavaGradleCustom from './Custom/JavaGradleCustom'; | |||
import ClangGCCCustom from './Custom/ClangGCCCustom'; | |||
import OtherCustom from './Custom/OtherCustom'; | |||
import { AnalysisCommandProps, AnalysisCommandRenderProps } from './utils'; | |||
import { AnalysisCommandCommon } from './AnalysisCommandOtherCI'; | |||
import { getHostUrl } from '../../../../helpers/urls'; | |||
import { getProjectKey } from '../ProjectAnalysisStep'; | |||
import { ProjectAnalysisModes } from '../ProjectAnalysisStepFromBuildTool'; | |||
import { RenderOS, RenderOSProps } from '../LanguageForm'; | |||
export function RenderCommandForMaven({ | |||
component, | |||
mode, | |||
onDone, | |||
organization, | |||
toggleModal, | |||
token | |||
}: AnalysisCommandRenderProps) { | |||
if (!token) { | |||
return null; | |||
} | |||
return ( | |||
<JavaMavenCustom | |||
host={getHostUrl()} | |||
mode={mode} | |||
onDone={onDone} | |||
organization={organization} | |||
projectKey={component && component.key} | |||
toggleModal={toggleModal} | |||
token={token} | |||
/> | |||
); | |||
} | |||
export function RenderCommandForGradle({ | |||
component, | |||
mode, | |||
onDone, | |||
organization, | |||
toggleModal, | |||
token | |||
}: AnalysisCommandRenderProps) { | |||
if (!token) { | |||
return null; | |||
} | |||
return ( | |||
<JavaGradleCustom | |||
host={getHostUrl()} | |||
mode={mode} | |||
onDone={onDone} | |||
organization={organization} | |||
projectKey={component && component.key} | |||
toggleModal={toggleModal} | |||
token={token} | |||
/> | |||
); | |||
} | |||
export function RenderCommandForClangOrGCC({ | |||
component, | |||
mode, | |||
onDone, | |||
organization, | |||
os, | |||
small, | |||
toggleModal, | |||
token | |||
}: AnalysisCommandRenderProps) { | |||
const projectKey = getProjectKey(undefined, component); | |||
if (!projectKey || !os || !token) { | |||
return null; | |||
} | |||
return ( | |||
<ClangGCCCustom | |||
host={getHostUrl()} | |||
mode={mode} | |||
onDone={onDone} | |||
organization={organization} | |||
os={os} | |||
projectKey={projectKey} | |||
small={small} | |||
toggleModal={toggleModal} | |||
token={token} | |||
/> | |||
); | |||
} | |||
export function RenderCommandForOther({ | |||
component, | |||
currentUser, | |||
mode, | |||
onDone, | |||
organization, | |||
os, | |||
toggleModal, | |||
token | |||
}: AnalysisCommandRenderProps) { | |||
const projectKey = getProjectKey(undefined, component); | |||
if (!component || !projectKey || !os || !token) { | |||
return null; | |||
} | |||
return ( | |||
<OtherCustom | |||
component={component} | |||
currentUser={currentUser} | |||
host={getHostUrl()} | |||
mode={mode} | |||
onDone={onDone} | |||
organization={organization} | |||
os={os} | |||
projectKey={projectKey} | |||
toggleModal={toggleModal} | |||
token={token} | |||
/> | |||
); | |||
} | |||
function getBuildOptions({ | |||
os, | |||
setOS | |||
}: RenderOSProps): { [k: string]: (props: AnalysisCommandRenderProps) => JSX.Element | null } { | |||
return { | |||
gradle: RenderCommandForGradle, | |||
make: function make(props: AnalysisCommandRenderProps) { | |||
return ( | |||
<> | |||
<RenderOS os={os} setOS={setOS} /> | |||
<RenderCommandForClangOrGCC {...props} /> | |||
</> | |||
); | |||
}, | |||
maven: RenderCommandForMaven, | |||
other: function other(props: AnalysisCommandRenderProps) { | |||
return ( | |||
<> | |||
<RenderOS os={os} setOS={setOS} /> | |||
<RenderCommandForOther {...props} /> | |||
</> | |||
); | |||
} | |||
}; | |||
} | |||
export default function AnalysisCommandCustom(props: AnalysisCommandProps) { | |||
return ( | |||
<AnalysisCommandCommon | |||
{...props} | |||
getBuildOptions={getBuildOptions} | |||
mode={ProjectAnalysisModes.Custom} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,174 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import OtherOtherCI from './OtherCI/OtherOtherCI'; | |||
import ClangGCCOtherCI from './OtherCI/ClangGCCOtherCI'; | |||
import { AnalysisCommandProps, AnalysisCommandRenderProps } from './utils'; | |||
import { RenderCommandForGradle, RenderCommandForMaven } from './AnalysisCommandCustom'; | |||
import { getHostUrl } from '../../../../helpers/urls'; | |||
import { getProjectKey } from '../ProjectAnalysisStep'; | |||
import { RenderOS, RenderOSProps } from '../LanguageForm'; | |||
import { ProjectAnalysisModes } from '../ProjectAnalysisStepFromBuildTool'; | |||
import EditTokenModal from '../../analyzeProject/steps/EditTokenModal'; | |||
export function RenderCommandForClangOrGCC({ | |||
component, | |||
onDone, | |||
organization, | |||
os, | |||
small, | |||
toggleModal, | |||
token | |||
}: AnalysisCommandRenderProps) { | |||
const projectKey = getProjectKey(undefined, component); | |||
if (!projectKey || !os || !token) { | |||
return null; | |||
} | |||
return ( | |||
<ClangGCCOtherCI | |||
host={getHostUrl()} | |||
onDone={onDone} | |||
organization={organization} | |||
os={os} | |||
projectKey={projectKey} | |||
small={small} | |||
toggleModal={toggleModal} | |||
token={token} | |||
/> | |||
); | |||
} | |||
export function RenderCommandForOther({ | |||
component, | |||
currentUser, | |||
onDone, | |||
organization, | |||
os, | |||
toggleModal, | |||
token | |||
}: AnalysisCommandRenderProps) { | |||
const projectKey = getProjectKey(undefined, component); | |||
if (!component || !projectKey || !os || !token) { | |||
return null; | |||
} | |||
return ( | |||
<OtherOtherCI | |||
component={component} | |||
currentUser={currentUser} | |||
host={getHostUrl()} | |||
onDone={onDone} | |||
organization={organization} | |||
os={os} | |||
projectKey={projectKey} | |||
toggleModal={toggleModal} | |||
token={token} | |||
/> | |||
); | |||
} | |||
function getBuildOptions({ | |||
os, | |||
setOS | |||
}: RenderOSProps): { [k: string]: (props: AnalysisCommandRenderProps) => JSX.Element | null } { | |||
return { | |||
gradle: RenderCommandForGradle, | |||
make: function make(props) { | |||
return ( | |||
<> | |||
<RenderOS os={os} setOS={setOS} /> | |||
<RenderCommandForClangOrGCC {...props} /> | |||
</> | |||
); | |||
}, | |||
maven: RenderCommandForMaven, | |||
other: function other(props) { | |||
return ( | |||
<> | |||
<RenderOS os={os} setOS={setOS} /> | |||
<RenderCommandForOther {...props} /> | |||
</> | |||
); | |||
} | |||
}; | |||
} | |||
interface AnalysisCommandExtraProps { | |||
mode: ProjectAnalysisModes; | |||
getBuildOptions: ( | |||
props: RenderOSProps | |||
) => { [k: string]: (props: AnalysisCommandRenderProps) => JSX.Element | null }; | |||
} | |||
export function AnalysisCommandCommon(props: AnalysisCommandProps & AnalysisCommandExtraProps) { | |||
const [os, setOS] = React.useState<string | undefined>(undefined); | |||
const [isModalVisible, toggleModal] = React.useState<boolean>(false); | |||
const { buildType } = props; | |||
if (!os && props.os) { | |||
setOS(props.os); | |||
} | |||
const toggleTokenModal = () => toggleModal(!isModalVisible); | |||
const close = () => toggleModal(false); | |||
const save = (t: string) => { | |||
props.setToken(t); | |||
close(); | |||
}; | |||
const callOnDone = () => { | |||
props.onDone({ os }); | |||
}; | |||
const Build = (buildType && props.getBuildOptions({ os, setOS })[buildType]) || undefined; | |||
return Build ? ( | |||
<> | |||
{isModalVisible && ( | |||
<EditTokenModal | |||
component={props.component} | |||
currentUser={props.currentUser} | |||
onClose={close} | |||
onSave={save} | |||
/> | |||
)} | |||
<Build | |||
{...props} | |||
mode={props.mode} | |||
onDone={callOnDone} | |||
os={os} | |||
toggleModal={toggleTokenModal} | |||
token={props.token} | |||
/> | |||
</> | |||
) : null; | |||
} | |||
export default function AnalysisCommandOtherCI(props: AnalysisCommandProps) { | |||
return ( | |||
<AnalysisCommandCommon | |||
{...props} | |||
getBuildOptions={getBuildOptions} | |||
mode={ProjectAnalysisModes.CI} | |||
/> | |||
); | |||
} |
@@ -0,0 +1,207 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { JavaMavenTravisSonarCloud } from './TravisSonarCloud/JavaMavenTravisSonarCloud'; | |||
import { JavaGradleTravisSonarCloud } from './TravisSonarCloud/JavaGradleTravisSonarCloud'; | |||
import { OtherTravisSonarCloud } from './TravisSonarCloud/OtherTravisSonarCloud'; | |||
import { ClangGCCTravisSonarCloud } from './TravisSonarCloud/ClangGCCTravisSonarCloud'; | |||
import { getHostUrl } from '../../../../helpers/urls'; | |||
import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import { getProjectKey } from '../ProjectAnalysisStep'; | |||
interface Props { | |||
buildType: string | undefined; | |||
component?: T.Component; | |||
organization?: string; | |||
small?: boolean; | |||
token?: string; | |||
} | |||
interface RenderProps { | |||
component?: T.Component; | |||
organization?: string; | |||
small?: boolean; | |||
token?: string; | |||
} | |||
export function getSonarcloudAddonYml(organization: string = '') { | |||
return `addons: | |||
sonarcloud: | |||
organization: ${organization ? `"${organization}"` : `"Add your organization key"`} | |||
token: | |||
secure: "**************************" # encrypted value of your token`; | |||
} | |||
export function getSonarcloudAddonYmlRender(organization: string = '') { | |||
return ( | |||
<> | |||
{`addons: | |||
sonarcloud: | |||
organization: ${organization ? `"${organization}"` : `"Add your organization key"`} | |||
token: | |||
secure: `} | |||
{ | |||
<span className="highlight"> | |||
{'"**************************"'} # encrypted value of your token | |||
</span> | |||
} | |||
<br /> | |||
</> | |||
); | |||
} | |||
export function RequirementJavaBuild() { | |||
return ( | |||
<> | |||
<p className="spacer-bottom">{translate('onboarding.analysis.with.travis.environments')}</p> | |||
<div className="flex-columns"> | |||
<div className="flex-column flex-column-half"> | |||
<a | |||
href="https://docs.travis-ci.com/user/reference/precise/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.analysis.with.travis.environment.image.java')} | |||
</a> | |||
<CodeSnippet isOneLine={true} noCopy={true} snippet={'language: java'} /> | |||
</div> | |||
<div className="display-flex-stretch"> | |||
<div className="vertical-pipe-separator"> | |||
<div className="vertical-separator " /> | |||
<span className="note">{translate('or')}</span> | |||
<div className="vertical-separator" /> | |||
</div> | |||
</div> | |||
<div className="flex-column flex-column-half"> | |||
<a | |||
href="https://docs.travis-ci.com/user/reference/trusty/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.analysis.with.travis.environment.image.ci')} | |||
</a> | |||
<CodeSnippet isOneLine={true} noCopy={true} snippet={'dist: trusty'} /> | |||
</div> | |||
</div> | |||
</> | |||
); | |||
} | |||
export function RequirementOtherBuild() { | |||
return ( | |||
<> | |||
<p> | |||
{translate('onboarding.analysis.with.travis.environment')}{' '} | |||
<a | |||
href="https://docs.travis-ci.com/user/reference/trusty/" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.analysis.with.travis.environment.image.ci')} | |||
</a> | |||
</p> | |||
<CodeSnippet isOneLine={true} noCopy={true} snippet={'dist: trusty'} /> | |||
</> | |||
); | |||
} | |||
export function RenderCommandForClangOrGCC({ component, organization, small, token }: RenderProps) { | |||
const projectKey = getProjectKey(undefined, component); | |||
if (!projectKey || !token) { | |||
return null; | |||
} | |||
return ( | |||
<ClangGCCTravisSonarCloud | |||
host={getHostUrl()} | |||
organization={organization} | |||
os="linux" | |||
projectKey={projectKey} | |||
small={small} | |||
token={token} | |||
/> | |||
); | |||
} | |||
export function RenderCommandForGradle({ component, organization, token }: RenderProps) { | |||
if (!token) { | |||
return null; | |||
} | |||
return ( | |||
<JavaGradleTravisSonarCloud | |||
host={getHostUrl()} | |||
organization={organization} | |||
projectKey={component && component.key} | |||
token={token} | |||
/> | |||
); | |||
} | |||
export function RenderCommandForMaven({ component, organization, token }: RenderProps) { | |||
if (!token) { | |||
return null; | |||
} | |||
return ( | |||
<JavaMavenTravisSonarCloud | |||
host={getHostUrl()} | |||
organization={organization} | |||
projectKey={component && component.key} | |||
token={token} | |||
/> | |||
); | |||
} | |||
export function RenderCommandForOther({ component, organization, token }: RenderProps) { | |||
const projectKey = getProjectKey(undefined, component); | |||
if (!projectKey || !token) { | |||
return null; | |||
} | |||
return ( | |||
<OtherTravisSonarCloud | |||
host={getHostUrl()} | |||
organization={organization} | |||
os={'linux'} | |||
projectKey={projectKey} | |||
token={token} | |||
/> | |||
); | |||
} | |||
function getBuildOptions(): { | |||
[k: string]: (props: Props) => JSX.Element | null; | |||
} { | |||
return { | |||
gradle: RenderCommandForGradle, | |||
make: RenderCommandForClangOrGCC, | |||
maven: RenderCommandForMaven, | |||
other: RenderCommandForOther | |||
}; | |||
} | |||
export default function AnalysisCommandTravis(props: Props) { | |||
const { buildType } = props; | |||
const Build = (buildType && getBuildOptions()[buildType]) || undefined; | |||
return Build ? <Build {...props} /> : null; | |||
} |
@@ -26,7 +26,7 @@ import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import { quote } from '../../utils'; | |||
interface Props { | |||
export interface Props { | |||
host: string; | |||
os: string; | |||
organization?: string; |
@@ -0,0 +1,132 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { quote } from '../../../utils'; | |||
import SQScanner from '../SQScanner'; | |||
import BuildWrapper from '../BuildWrapper'; | |||
import { translate } from '../../../../../helpers/l10n'; | |||
import CodeSnippet from '../../../../../components/common/CodeSnippet'; | |||
import { Button, EditButton } from '../../../../../components/ui/buttons'; | |||
import { ProjectAnalysisModes } from '../../ProjectAnalysisStepFromBuildTool'; | |||
export interface Props { | |||
host: string; | |||
mode: ProjectAnalysisModes; | |||
onDone: VoidFunction; | |||
os: string; | |||
organization?: string; | |||
projectKey: string; | |||
small?: boolean; | |||
toggleModal: VoidFunction; | |||
token: string; | |||
} | |||
const executables: T.Dict<string> = { | |||
linux: 'build-wrapper-linux-x86-64', | |||
win: 'build-wrapper-win-x86-64.exe', | |||
mac: 'build-wrapper-macosx-x86' | |||
}; | |||
interface ClangGCCProps extends Pick<Props, 'small' | 'onDone' | 'os'> { | |||
command1: string; | |||
command2: (string | undefined)[]; | |||
renderCommand2: () => JSX.Element; | |||
} | |||
export function ClangGCCCommon(props: ClangGCCProps) { | |||
return ( | |||
<> | |||
<h4 className="huge-spacer-top spacer-bottom"> | |||
{translate('onboarding.analysis.sq_scanner.execute')} | |||
</h4> | |||
<p className="spacer-bottom markdown"> | |||
{translate('onboarding.analysis.sq_scanner.execute.text.custom')} | |||
</p> | |||
<CodeSnippet isOneLine={props.small} snippet={props.command1} /> | |||
<CodeSnippet | |||
isOneLine={props.os === 'win'} | |||
render={props.renderCommand2} | |||
snippet={props.command2} | |||
wrap={true} | |||
/> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.sq_scanner.docs')} | |||
id="onboarding.analysis.sq_scanner.docs" | |||
values={{ | |||
link: ( | |||
<a | |||
href="http://redirect.sonarsource.com/doc/install-configure-scanner.html" | |||
rel="noopener noreferrer" | |||
target="_blank"> | |||
{translate('onboarding.analysis.sq_scanner.docs_link')} | |||
</a> | |||
) | |||
}} | |||
/> | |||
<div className="big-spacer-top"> | |||
<Button className="js-continue" onClick={props.onDone}> | |||
{translate('onboarding.finish')} | |||
</Button> | |||
</div> | |||
</> | |||
); | |||
} | |||
export default function ClangGCCCustom(props: Props) { | |||
const command1 = `${executables[props.os]} --out-dir bw-output make clean all`; | |||
const q = quote(props.os); | |||
const command2 = [ | |||
props.os === 'win' ? 'sonar-scanner.bat' : 'sonar-scanner', | |||
'-D' + q(`sonar.projectKey=${props.projectKey}`), | |||
props.organization && '-D' + q(`sonar.organization=${props.organization}`), | |||
'-D' + q('sonar.sources=.'), | |||
'-D' + q('sonar.cfamily.build-wrapper-output=bw-output'), | |||
'-D' + q(`sonar.host.url=${props.host}`), | |||
'-D' + q(`sonar.login=${props.token}`) | |||
]; | |||
const renderCommand2 = () => ( | |||
<> | |||
{command2.join(' \\\n ')}{' '} | |||
<EditButton className="edit-token spacer-left" onClick={props.toggleModal} /> | |||
</> | |||
); | |||
return ( | |||
<div className="huge-spacer-top"> | |||
<SQScanner os={props.os} /> | |||
<BuildWrapper className="huge-spacer-top" os={props.os} /> | |||
<ClangGCCCommon | |||
command1={command1} | |||
command2={command2} | |||
onDone={props.onDone} | |||
os={props.os} | |||
renderCommand2={renderCommand2} | |||
/> | |||
</div> | |||
); | |||
} |
@@ -0,0 +1,69 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { JavaCustomProps, RenderCustomContent } from './JavaMavenCustom'; | |||
import { translate } from '../../../../../helpers/l10n'; | |||
import CodeSnippet from '../../../../../components/common/CodeSnippet'; | |||
import { ProjectAnalysisModes } from '../../ProjectAnalysisStepFromBuildTool'; | |||
export default function JavaGradleCustom(props: JavaCustomProps) { | |||
const suffix = props.mode === ProjectAnalysisModes.CI ? '.ci' : ''; | |||
const config = 'plugins {\n id "org.sonarqube" version "2.7"\n}'; | |||
const command = [ | |||
'./gradlew sonarqube', | |||
props.projectKey && `-Dsonar.projectKey=${props.projectKey}`, | |||
props.organization && `-Dsonar.organization=${props.organization}`, | |||
`-Dsonar.host.url=${props.host}`, | |||
`-Dsonar.login=${props.token}` | |||
]; | |||
return ( | |||
<div> | |||
<h4 className="spacer-bottom"> | |||
{translate(`onboarding.analysis.java.gradle.header${suffix}`)} | |||
</h4> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.java.gradle.text.1.sonarcloud')} | |||
id="onboarding.analysis.java.gradle.text.1.sonarcloud" | |||
values={{ | |||
file: <code>build.gradle</code>, | |||
plugin: <code>org.sonarqube</code> | |||
}} | |||
/> | |||
<CodeSnippet snippet={config} /> | |||
<p className="spacer-top spacer-bottom markdown"> | |||
{translate('onboarding.analysis.java.gradle.text.2')} | |||
</p> | |||
<RenderCustomContent | |||
command={command} | |||
linkText="onboarding.analysis.java.gradle.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/gradle.html" | |||
onDone={props.onDone} | |||
toggleModal={props.toggleModal} | |||
/> | |||
</div> | |||
); | |||
} |
@@ -0,0 +1,130 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { FormattedMessage } from 'react-intl'; | |||
import { translate } from '../../../../../helpers/l10n'; | |||
import InstanceMessage from '../../../../../components/common/InstanceMessage'; | |||
import CodeSnippet from '../../../../../components/common/CodeSnippet'; | |||
import { Button, EditButton } from '../../../../../components/ui/buttons'; | |||
import { ProjectAnalysisModes } from '../../ProjectAnalysisStepFromBuildTool'; | |||
export interface JavaCustomProps { | |||
host: string; | |||
mode: ProjectAnalysisModes; | |||
onDone: VoidFunction; | |||
organization?: string; | |||
projectKey?: string; | |||
toggleModal: VoidFunction; | |||
token: string; | |||
} | |||
interface RenderCustomCommandProps { | |||
command: (string | undefined)[]; | |||
toggleModal: VoidFunction; | |||
} | |||
export function RenderCustomCommand({ | |||
command, | |||
toggleModal | |||
}: RenderCustomCommandProps): JSX.Element { | |||
return ( | |||
<> | |||
{command.join(' \\\n ')}{' '} | |||
<EditButton className="edit-token spacer-left" onClick={toggleModal} /> | |||
</> | |||
); | |||
} | |||
interface RenderCustomContent { | |||
linkText: string; | |||
linkUrl: string; | |||
onDone: VoidFunction; | |||
} | |||
export function RenderCustomContent({ | |||
command, | |||
linkText, | |||
linkUrl, | |||
onDone, | |||
toggleModal | |||
}: RenderCustomCommandProps & RenderCustomContent) { | |||
return ( | |||
<> | |||
<CodeSnippet | |||
render={() => <RenderCustomCommand command={command} toggleModal={toggleModal} />} | |||
snippet={command} | |||
wrap={true} | |||
/> | |||
<p className="big-spacer-top markdown"> | |||
<FormattedMessage | |||
defaultMessage={translate('onboarding.analysis.docs')} | |||
id="onboarding.analysis.docs" | |||
values={{ | |||
link: ( | |||
<a href={linkUrl} rel="noopener noreferrer" target="_blank"> | |||
{translate(linkText)} | |||
</a> | |||
) | |||
}} | |||
/> | |||
</p> | |||
<div className="big-spacer-top"> | |||
<Button className="js-continue" onClick={onDone}> | |||
{translate('onboarding.finish')} | |||
</Button> | |||
</div> | |||
</> | |||
); | |||
} | |||
export default function JavaMavenCustom(props: JavaCustomProps) { | |||
const suffix = props.mode === ProjectAnalysisModes.CI ? '.ci' : ''; | |||
const command = [ | |||
'mvn sonar:sonar', | |||
props.projectKey && `-Dsonar.projectKey=${props.projectKey}`, | |||
props.organization && `-Dsonar.organization=${props.organization}`, | |||
`-Dsonar.host.url=${props.host}`, | |||
`-Dsonar.login=${props.token}` | |||
]; | |||
return ( | |||
<div> | |||
<h4 className="spacer-bottom"> | |||
{translate(`onboarding.analysis.java.maven.header${suffix}`)} | |||
</h4> | |||
<p className="spacer-bottom markdown"> | |||
<InstanceMessage | |||
message={translate(`onboarding.analysis.java.maven.text.custom${suffix}`)} | |||
/> | |||
</p> | |||
<RenderCustomContent | |||
command={command} | |||
linkText="onboarding.analysis.java.maven.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/install-configure-scanner-maven.html" | |||
onDone={props.onDone} | |||
toggleModal={props.toggleModal} | |||
/> | |||
</div> | |||
); | |||
} |
@@ -0,0 +1,96 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import SQScanner from '..//SQScanner'; | |||
import CodeSnippet from '../../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../../components/common/InstanceMessage'; | |||
import { translate } from '../../../../../helpers/l10n'; | |||
import { quote } from '../../../utils'; | |||
import { Button, EditButton } from '../../../../../components/ui/buttons'; | |||
import { ProjectAnalysisModes } from '../../ProjectAnalysisStepFromBuildTool'; | |||
export interface Props { | |||
component: T.Component; | |||
currentUser: T.LoggedInUser; | |||
host: string; | |||
mode: ProjectAnalysisModes; | |||
onDone: VoidFunction; | |||
organization?: string; | |||
os: string; | |||
projectKey: string; | |||
toggleModal: VoidFunction; | |||
token: string; | |||
} | |||
export default function OtherCustom(props: Props) { | |||
const q = quote(props.os); | |||
const command = [ | |||
props.os === 'win' ? 'sonar-scanner.bat' : 'sonar-scanner', | |||
'-D' + q(`sonar.projectKey=${props.projectKey}`), | |||
props.organization && '-D' + q(`sonar.organization=${props.organization}`), | |||
'-D' + q('sonar.sources=.'), | |||
'-D' + q(`sonar.host.url=${props.host}`), | |||
'-D' + q(`sonar.login=${props.token}`) | |||
]; | |||
const renderCommand = () => ( | |||
<> | |||
{command.join(' \\\n ')}{' '} | |||
<EditButton className="edit-token spacer-left" onClick={props.toggleModal} /> | |||
</> | |||
); | |||
return ( | |||
<div className="huge-spacer-top"> | |||
<SQScanner os={props.os} /> | |||
<h4 className="huge-spacer-top spacer-bottom"> | |||
{translate('onboarding.analysis.sq_scanner.execute')} | |||
</h4> | |||
<InstanceMessage message={translate('onboarding.analysis.sq_scanner.execute.text.custom')}> | |||
{transformedMessage => ( | |||
<p | |||
className="spacer-bottom markdown" | |||
dangerouslySetInnerHTML={{ __html: transformedMessage }} | |||
/> | |||
)} | |||
</InstanceMessage> | |||
<CodeSnippet | |||
isOneLine={props.os === 'win'} | |||
render={renderCommand} | |||
snippet={command} | |||
wrap={true} | |||
/> | |||
<p | |||
className="big-spacer-top markdown" | |||
dangerouslySetInnerHTML={{ __html: translate('onboarding.analysis.standard.docs') }} | |||
/> | |||
<div className="big-spacer-top"> | |||
<Button className="js-continue" onClick={props.onDone}> | |||
{translate('onboarding.finish')} | |||
</Button> | |||
</div> | |||
</div> | |||
); | |||
} |
@@ -0,0 +1,58 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import ClangGCCCustom, { ClangGCCCommon } from '../ClangGCCCustom'; | |||
import { ProjectAnalysisModes } from '../../../ProjectAnalysisStepFromBuildTool'; | |||
it('should render correctly', () => { | |||
expect( | |||
shallow( | |||
<ClangGCCCustom | |||
host="https://sonarcloud.io" | |||
mode={ProjectAnalysisModes.Custom} | |||
onDone={jest.fn()} | |||
organization="use-the-force" | |||
os="linux" | |||
projectKey="luke-lightsaber" | |||
small={true} | |||
toggleModal={jest.fn()} | |||
token="sonarsource123" | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render common elements correctly', () => { | |||
const command1 = `command1`; | |||
const command2 = [`command2`]; | |||
const renderCommand2 = () => <>render command 2</>; | |||
expect( | |||
shallow( | |||
<ClangGCCCommon | |||
command1={command1} | |||
command2={command2} | |||
renderCommand2={renderCommand2} | |||
onDone={jest.fn()} | |||
os="linux" | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,67 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import { ProjectAnalysisModes } from '../../../ProjectAnalysisStepFromBuildTool'; | |||
import JavaGradleCustom from '../JavaGradleCustom'; | |||
import { RenderCustomContent } from '../JavaMavenCustom'; | |||
const host = 'https://sonarcloud.io'; | |||
const organization = 'use-the-force'; | |||
const projectKey = 'luke-lightsaber'; | |||
const token = 'sonarsource123'; | |||
it('should render correctly', () => { | |||
expect( | |||
shallow( | |||
<JavaGradleCustom | |||
host={host} | |||
mode={ProjectAnalysisModes.Custom} | |||
onDone={jest.fn()} | |||
organization={organization} | |||
projectKey={projectKey} | |||
toggleModal={jest.fn()} | |||
token={token} | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render gradle custom content', () => { | |||
const command = [ | |||
'./gradlew sonarqube', | |||
projectKey && `-Dsonar.projectKey=${projectKey}`, | |||
organization && `-Dsonar.organization=${organization}`, | |||
`-Dsonar.host.url=${host}`, | |||
`-Dsonar.login=${token}` | |||
]; | |||
const onDone = jest.fn(); | |||
const toggleModal = jest.fn(); | |||
expect( | |||
<RenderCustomContent | |||
command={command} | |||
linkText="onboarding.analysis.java.gradle.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/gradle.html" | |||
onDone={onDone} | |||
toggleModal={toggleModal} | |||
/> | |||
).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,80 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import { ProjectAnalysisModes } from '../../../ProjectAnalysisStepFromBuildTool'; | |||
import JavaMavenCustom, { RenderCustomContent } from '../JavaMavenCustom'; | |||
const host = 'https://sonarcloud.io'; | |||
const organization = 'use-the-force'; | |||
const projectKey = 'luke-lightsaber'; | |||
const token = 'sonarsource123'; | |||
it('should render correctly', () => { | |||
expect( | |||
shallow( | |||
<JavaMavenCustom | |||
host={host} | |||
mode={ProjectAnalysisModes.Custom} | |||
onDone={jest.fn()} | |||
organization={organization} | |||
projectKey={projectKey} | |||
toggleModal={jest.fn()} | |||
token={token} | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render common elements correctly', () => { | |||
expect( | |||
shallow( | |||
<JavaMavenCustom | |||
host="sonarcloud" | |||
mode={ProjectAnalysisModes.Custom} | |||
onDone={jest.fn()} | |||
toggleModal={jest.fn()} | |||
token="123" | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); | |||
it('should render maven custom content', () => { | |||
const command = [ | |||
'mvn sonar:sonar', | |||
projectKey && `-Dsonar.projectKey=${projectKey}`, | |||
organization && `-Dsonar.organization=${organization}`, | |||
`-Dsonar.host.url=${host}`, | |||
`-Dsonar.login=${token}` | |||
]; | |||
const onDone = jest.fn(); | |||
const toggleModal = jest.fn(); | |||
expect( | |||
<RenderCustomContent | |||
command={command} | |||
linkText="onboarding.analysis.java.maven.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/install-configure-scanner-maven.html" | |||
onDone={onDone} | |||
toggleModal={toggleModal} | |||
/> | |||
).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,43 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { shallow } from 'enzyme'; | |||
import { ProjectAnalysisModes } from '../../../ProjectAnalysisStepFromBuildTool'; | |||
import OtherCustom from '../OtherCustom'; | |||
import { mockComponent, mockLoggedInUser } from '../../../../../../helpers/testMocks'; | |||
it('should render correctly', () => { | |||
expect( | |||
shallow( | |||
<OtherCustom | |||
component={mockComponent()} | |||
currentUser={mockLoggedInUser()} | |||
host="https://sonarcloud.io" | |||
mode={ProjectAnalysisModes.Custom} | |||
onDone={jest.fn()} | |||
organization="use-the-force" | |||
os="linux" | |||
projectKey="luke-lightsaber" | |||
toggleModal={jest.fn()} | |||
token="sonarsource123" | |||
/> | |||
) | |||
).toMatchSnapshot(); | |||
}); |
@@ -0,0 +1,85 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render common elements correctly 1`] = ` | |||
<Fragment> | |||
<h4 | |||
className="huge-spacer-top spacer-bottom" | |||
> | |||
onboarding.analysis.sq_scanner.execute | |||
</h4> | |||
<p | |||
className="spacer-bottom markdown" | |||
> | |||
onboarding.analysis.sq_scanner.execute.text.custom | |||
</p> | |||
<CodeSnippet | |||
snippet="command1" | |||
/> | |||
<CodeSnippet | |||
isOneLine={false} | |||
render={[Function]} | |||
snippet={ | |||
Array [ | |||
"command2", | |||
] | |||
} | |||
wrap={true} | |||
/> | |||
<FormattedMessage | |||
defaultMessage="onboarding.analysis.sq_scanner.docs" | |||
id="onboarding.analysis.sq_scanner.docs" | |||
values={ | |||
Object { | |||
"link": <a | |||
href="http://redirect.sonarsource.com/doc/install-configure-scanner.html" | |||
rel="noopener noreferrer" | |||
target="_blank" | |||
> | |||
onboarding.analysis.sq_scanner.docs_link | |||
</a>, | |||
} | |||
} | |||
/> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<Button | |||
className="js-continue" | |||
onClick={[MockFunction]} | |||
> | |||
onboarding.finish | |||
</Button> | |||
</div> | |||
</Fragment> | |||
`; | |||
exports[`should render correctly 1`] = ` | |||
<div | |||
className="huge-spacer-top" | |||
> | |||
<SQScanner | |||
os="linux" | |||
/> | |||
<BuildWrapper | |||
className="huge-spacer-top" | |||
os="linux" | |||
/> | |||
<ClangGCCCommon | |||
command1="build-wrapper-linux-x86-64 --out-dir bw-output make clean all" | |||
command2={ | |||
Array [ | |||
"sonar-scanner", | |||
"-Dsonar.projectKey=luke-lightsaber", | |||
"-Dsonar.organization=use-the-force", | |||
"-Dsonar.sources=.", | |||
"-Dsonar.cfamily.build-wrapper-output=bw-output", | |||
"-Dsonar.host.url=https://sonarcloud.io", | |||
"-Dsonar.login=sonarsource123", | |||
] | |||
} | |||
onDone={[MockFunction]} | |||
os="linux" | |||
renderCommand2={[Function]} | |||
/> | |||
</div> | |||
`; |
@@ -0,0 +1,68 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.analysis.java.gradle.header | |||
</h4> | |||
<FormattedMessage | |||
defaultMessage="onboarding.analysis.java.gradle.text.1.sonarcloud" | |||
id="onboarding.analysis.java.gradle.text.1.sonarcloud" | |||
values={ | |||
Object { | |||
"file": <code> | |||
build.gradle | |||
</code>, | |||
"plugin": <code> | |||
org.sonarqube | |||
</code>, | |||
} | |||
} | |||
/> | |||
<CodeSnippet | |||
snippet="plugins { | |||
id \\"org.sonarqube\\" version \\"2.7\\" | |||
}" | |||
/> | |||
<p | |||
className="spacer-top spacer-bottom markdown" | |||
> | |||
onboarding.analysis.java.gradle.text.2 | |||
</p> | |||
<RenderCustomContent | |||
command={ | |||
Array [ | |||
"./gradlew sonarqube", | |||
"-Dsonar.projectKey=luke-lightsaber", | |||
"-Dsonar.organization=use-the-force", | |||
"-Dsonar.host.url=https://sonarcloud.io", | |||
"-Dsonar.login=sonarsource123", | |||
] | |||
} | |||
linkText="onboarding.analysis.java.gradle.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/gradle.html" | |||
onDone={[MockFunction]} | |||
toggleModal={[MockFunction]} | |||
/> | |||
</div> | |||
`; | |||
exports[`should render gradle custom content 1`] = ` | |||
<RenderCustomContent | |||
command={ | |||
Array [ | |||
"./gradlew sonarqube", | |||
"-Dsonar.projectKey=luke-lightsaber", | |||
"-Dsonar.organization=use-the-force", | |||
"-Dsonar.host.url=https://sonarcloud.io", | |||
"-Dsonar.login=sonarsource123", | |||
] | |||
} | |||
linkText="onboarding.analysis.java.gradle.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/gradle.html" | |||
onDone={[MockFunction]} | |||
toggleModal={[MockFunction]} | |||
/> | |||
`; |
@@ -0,0 +1,83 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render common elements correctly 1`] = ` | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.analysis.java.maven.header | |||
</h4> | |||
<p | |||
className="spacer-bottom markdown" | |||
> | |||
<InstanceMessage | |||
message="onboarding.analysis.java.maven.text.custom" | |||
/> | |||
</p> | |||
<RenderCustomContent | |||
command={ | |||
Array [ | |||
"mvn sonar:sonar", | |||
undefined, | |||
undefined, | |||
"-Dsonar.host.url=sonarcloud", | |||
"-Dsonar.login=123", | |||
] | |||
} | |||
linkText="onboarding.analysis.java.maven.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/install-configure-scanner-maven.html" | |||
onDone={[MockFunction]} | |||
toggleModal={[MockFunction]} | |||
/> | |||
</div> | |||
`; | |||
exports[`should render correctly 1`] = ` | |||
<div> | |||
<h4 | |||
className="spacer-bottom" | |||
> | |||
onboarding.analysis.java.maven.header | |||
</h4> | |||
<p | |||
className="spacer-bottom markdown" | |||
> | |||
<InstanceMessage | |||
message="onboarding.analysis.java.maven.text.custom" | |||
/> | |||
</p> | |||
<RenderCustomContent | |||
command={ | |||
Array [ | |||
"mvn sonar:sonar", | |||
"-Dsonar.projectKey=luke-lightsaber", | |||
"-Dsonar.organization=use-the-force", | |||
"-Dsonar.host.url=https://sonarcloud.io", | |||
"-Dsonar.login=sonarsource123", | |||
] | |||
} | |||
linkText="onboarding.analysis.java.maven.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/install-configure-scanner-maven.html" | |||
onDone={[MockFunction]} | |||
toggleModal={[MockFunction]} | |||
/> | |||
</div> | |||
`; | |||
exports[`should render maven custom content 1`] = ` | |||
<RenderCustomContent | |||
command={ | |||
Array [ | |||
"mvn sonar:sonar", | |||
"-Dsonar.projectKey=luke-lightsaber", | |||
"-Dsonar.organization=use-the-force", | |||
"-Dsonar.host.url=https://sonarcloud.io", | |||
"-Dsonar.login=sonarsource123", | |||
] | |||
} | |||
linkText="onboarding.analysis.java.maven.docs_link" | |||
linkUrl="http://redirect.sonarsource.com/doc/install-configure-scanner-maven.html" | |||
onDone={[MockFunction]} | |||
toggleModal={[MockFunction]} | |||
/> | |||
`; |
@@ -0,0 +1,54 @@ | |||
// Jest Snapshot v1, https://goo.gl/fbAQLP | |||
exports[`should render correctly 1`] = ` | |||
<div | |||
className="huge-spacer-top" | |||
> | |||
<SQScanner | |||
os="linux" | |||
/> | |||
<h4 | |||
className="huge-spacer-top spacer-bottom" | |||
> | |||
onboarding.analysis.sq_scanner.execute | |||
</h4> | |||
<InstanceMessage | |||
message="onboarding.analysis.sq_scanner.execute.text.custom" | |||
> | |||
<Component /> | |||
</InstanceMessage> | |||
<CodeSnippet | |||
isOneLine={false} | |||
render={[Function]} | |||
snippet={ | |||
Array [ | |||
"sonar-scanner", | |||
"-Dsonar.projectKey=luke-lightsaber", | |||
"-Dsonar.organization=use-the-force", | |||
"-Dsonar.sources=.", | |||
"-Dsonar.host.url=https://sonarcloud.io", | |||
"-Dsonar.login=sonarsource123", | |||
] | |||
} | |||
wrap={true} | |||
/> | |||
<p | |||
className="big-spacer-top markdown" | |||
dangerouslySetInnerHTML={ | |||
Object { | |||
"__html": "onboarding.analysis.standard.docs", | |||
} | |||
} | |||
/> | |||
<div | |||
className="big-spacer-top" | |||
> | |||
<Button | |||
className="js-continue" | |||
onClick={[MockFunction]} | |||
> | |||
onboarding.finish | |||
</Button> | |||
</div> | |||
</div> | |||
`; |
@@ -24,7 +24,7 @@ import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
interface Props { | |||
export interface Props { | |||
host: string; | |||
organization?: string; | |||
projectKey: string; |
@@ -23,7 +23,7 @@ import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
interface Props { | |||
export interface Props { | |||
host: string; | |||
organization?: string; | |||
projectKey?: string; |
@@ -23,7 +23,7 @@ import CodeSnippet from '../../../../components/common/CodeSnippet'; | |||
import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
interface Props { | |||
export interface Props { | |||
host: string; | |||
organization?: string; | |||
projectKey?: string; |
@@ -25,7 +25,7 @@ import InstanceMessage from '../../../../components/common/InstanceMessage'; | |||
import { translate } from '../../../../helpers/l10n'; | |||
import { quote } from '../../utils'; | |||
interface Props { | |||
export interface Props { | |||
host: string; | |||
organization?: string; | |||
os: string; |
@@ -0,0 +1,108 @@ | |||
/* | |||
* SonarQube | |||
* Copyright (C) 2009-2019 SonarSource SA | |||
* mailto:info AT sonarsource DOT com | |||
* | |||
* This program 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. | |||
* | |||
* This program 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. | |||
*/ | |||
import * as React from 'react'; | |||
import { quote } from '../../../utils'; | |||
import SQScanner from '../SQScanner'; | |||
import BuildWrapper from '../BuildWrapper'; | |||
import { translate } from '../../../../../helpers/l10n'; | |||
import CodeSnippet from '../../../../../components/common/CodeSnippet'; | |||
import { EditButton } from '../../../../../components/ui/buttons'; | |||
import { ClangGCCCommon } from '../Custom/ClangGCCCustom'; | |||
export interface Props { | |||
host: string; | |||
onDone: VoidFunction; | |||
os: string; | |||
organization?: string; | |||
projectKey: string; | |||
small?: boolean; | |||
toggleModal: VoidFunction; | |||
token: string; | |||
} | |||
const executables: T.Dict<string> = { | |||
linux: 'build-wrapper-linux-x86-64', | |||
win: 'build-wrapper-win-x86-64.exe', | |||
mac: 'build-wrapper-macosx-x86' | |||
}; | |||
export default function ClangGCCOtherCI(props: Props) { | |||
const command1 = `${executables[props.os]} --out-dir bw-output make clean all`; | |||
const q = quote(props.os); | |||
const command2 = [ | |||
props.os === 'win' ? 'sonar-scanner.bat' : 'sonar-scanner', | |||
'-D' + q(`sonar.projectKey=${props.projectKey}`), | |||
props.organization && '-D' + q(`sonar.organization=${props.organization}`), | |||
'-D' + q('sonar.sources=.'), | |||
'-D' + q('sonar.cfamily.build-wrapper-output=bw-output'), | |||
'-D' + q(`sonar.host.url=${props.host}`), | |||
'-D' + q(`sonar.login=${props.token}`) | |||
]; | |||
const renderCommand2 = () => ( | |||
<> | |||
{command2.join(' \\\n ')}{' '} | |||
<EditButton className="edit-token spacer-left" onClick={props.toggleModal} /> | |||
</> | |||
); | |||
const commandLinuxMac = ` | |||
local SONAR_SCANNER_VERSION=${translate('onboarding.analysis.sonar_scanner_version')} | |||
export SONAR_SCANNER_HOME=$HOME/.sonar/sonar-scanner-$SONAR_SCANNER_VERSION | |||
rm -rf $SONAR_SCANNER_HOME | |||
mkdir -p $SONAR_SCANNER_HOME | |||
curl -sSLo $HOME/.sonar/sonar-scanner.zip http://repo1.maven.org/maven2/org/sonarsource/scanner/cli/sonar-scanner-cli/$SONAR_SCANNER_VERSION/sonar-scanner-cli-$SONAR_SCANNER_VERSION.zip | |||
unzip $HOME/.sonar/sonar-scanner.zip -d $HOME/.sonar/ | |||
rm $HOME/.sonar/sonar-scanner.zip | |||
export PATH=$SONAR_SCANNER_HOME/bin:$PATH | |||
export SONAR_SCANNER_OPTS="-server" | |||
curl -LsS https://sonarcloud.io/static/cpp/build-wrapper-linux-x86.zip > build-wrapper-linux-x86.zip | |||
unzip build-wrapper-linux-x86.zip`; | |||
return ( | |||
<div className="huge-spacer-top"> | |||
{props.os === 'win' ? ( | |||
<> | |||
<SQScanner os={'ci'} /> | |||
<BuildWrapper className="huge-spacer-top" os={'ci'} /> | |||
</> | |||
) : ( | |||
<> | |||
<h4 className="huge-spacer-top spacer-bottom"> | |||
{translate('onboarding.analysis.sq_scanner.header.ci')} | |||
</h4> | |||
<CodeSnippet snippet={commandLinuxMac} /> | |||
</> | |||
)} | |||
<ClangGCCCommon | |||
command1={command1} | |||
command2={command2} | |||
renderCommand2={renderCommand2} | |||
onDone={props.onDone} | |||
os={props.os} | |||
/> | |||
</div> | |||
); | |||
} |