diff options
-rw-r--r-- | config/karma.config.js | 26 | ||||
-rw-r--r-- | doc/user/admin_area/settings/continuous_integration.md | 16 | ||||
-rw-r--r-- | doc/user/admin_area/settings/email.md | 24 | ||||
-rw-r--r-- | doc/user/admin_area/settings/external_authorization.md | 16 | ||||
-rw-r--r-- | package.json | 2 | ||||
-rwxr-xr-x | scripts/frontend/test.js | 114 |
6 files changed, 189 insertions, 9 deletions
diff --git a/config/karma.config.js b/config/karma.config.js index b2fc3a32816..2a5bf3581e0 100644 --- a/config/karma.config.js +++ b/config/karma.config.js @@ -9,11 +9,22 @@ const IS_EE = require('./helpers/is_ee_env'); const ROOT_PATH = path.resolve(__dirname, '..'); const SPECS_PATH = /^(?:\.[\\\/])?(ee[\\\/])?spec[\\\/]javascripts[\\\/]/; -function fatalError(message) { +function exitError(message) { console.error(chalk.red(`\nError: ${message}\n`)); process.exit(1); } +function exitWarn(message) { + console.error(chalk.yellow(`\nWarn: ${message}\n`)); + process.exit(0); +} + +function exit(message, isError = true) { + const fn = isError ? exitError : exitWarn; + + fn(message); +} + // disable problematic options webpackConfig.entry = undefined; webpackConfig.mode = 'development'; @@ -31,7 +42,8 @@ webpackConfig.plugins.push( }), ); -const specFilters = argumentsParser +const options = argumentsParser + .option('--no-fail-on-empty-test-suite') .option( '-f, --filter-spec [filter]', 'Filter run spec files by path. Multiple filters are like a logical OR.', @@ -41,7 +53,9 @@ const specFilters = argumentsParser }, [], ) - .parse(process.argv).filterSpec; + .parse(process.argv); + +const specFilters = options.filterSpec; const createContext = (specFiles, regex, suffix) => { const newContext = specFiles.reduce((context, file) => { @@ -73,11 +87,13 @@ if (specFilters.length) { filteredSpecFiles = [...new Set(filteredSpecFiles)]; if (filteredSpecFiles.length < 1) { - fatalError('Your filter did not match any test files.'); + const isError = options.failOnEmptyTestSuite; + + exit('Your filter did not match any test files.', isError); } if (!filteredSpecFiles.every(file => SPECS_PATH.test(file))) { - fatalError('Test files must be located within /spec/javascripts.'); + exitError('Test files must be located within /spec/javascripts.'); } const CE_FILES = filteredSpecFiles.filter(file => !file.startsWith('ee')); diff --git a/doc/user/admin_area/settings/continuous_integration.md b/doc/user/admin_area/settings/continuous_integration.md index 9dd476656ed..6c4abce83c2 100644 --- a/doc/user/admin_area/settings/continuous_integration.md +++ b/doc/user/admin_area/settings/continuous_integration.md @@ -1,3 +1,7 @@ +--- +type: reference +--- + # Continuous Integration and Deployment Admin settings **[CORE ONLY]** In this area, you will find settings for Auto DevOps, Runners and job artifacts. @@ -145,3 +149,15 @@ To set the duration for which the jobs will be considered as old and expired: Once that time passes, the jobs will be archived and no longer able to be retried. Make it empty to never expire jobs. It has to be no less than 1 day, for example: <code>15 days</code>, <code>1 month</code>, <code>2 years</code>. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. -->
\ No newline at end of file diff --git a/doc/user/admin_area/settings/email.md b/doc/user/admin_area/settings/email.md index 01a98cf15dc..912c2cff481 100644 --- a/doc/user/admin_area/settings/email.md +++ b/doc/user/admin_area/settings/email.md @@ -1,12 +1,18 @@ +--- +type: reference +--- + # Email +You can customize some of the content in emails sent from your GitLab instance. + ## Custom logo The logo in the header of some emails can be customized, see the [logo customization section](../../../customization/branded_page_and_email_header.md). ## Custom additional text **[PREMIUM ONLY]** ->[Introduced][ee-5031] in [GitLab Premium][eep] 10.7. +> [Introduced][ee-5031] in [GitLab Premium][eep] 10.7. The additional text will appear at the bottom of any email and can be used for legal/auditing/compliance reasons. @@ -24,8 +30,8 @@ legal/auditing/compliance reasons. > [Introduced](https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/22560) in GitLab 11.5. -This configuration option sets the email hostname for [private commit emails](../../profile/index.md#private-commit-email), -and it's, by default, set to `users.noreply.YOUR_CONFIGURED_HOSTNAME`. +This configuration option sets the email hostname for [private commit emails](../../profile/index.md#private-commit-email). + By default it is set to `users.noreply.YOUR_CONFIGURED_HOSTNAME`. In order to change this option: @@ -36,3 +42,15 @@ In order to change this option: NOTE: **Note**: Once the hostname gets configured, every private commit email using the previous hostname, will not get recognized by GitLab. This can directly conflict with certain [Push rules](https://docs.gitlab.com/ee/push_rules/push_rules.html) such as `Check whether author is a GitLab user` and `Check whether committer is the current authenticated user`. + +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. -->
\ No newline at end of file diff --git a/doc/user/admin_area/settings/external_authorization.md b/doc/user/admin_area/settings/external_authorization.md index 06e00e02f3d..11c0867da17 100644 --- a/doc/user/admin_area/settings/external_authorization.md +++ b/doc/user/admin_area/settings/external_authorization.md @@ -1,3 +1,7 @@ +--- +type: reference +--- + # External authorization control **[CORE ONLY]** > [Introduced](https://gitlab.com/gitlab-org/gitlab-ee/issues/4216) in @@ -108,5 +112,17 @@ The label will be shown on all project pages in the upper right corner. ![classification label on project page](img/classification_label_on_project_page.png) +<!-- ## Troubleshooting + +Include any troubleshooting steps that you can foresee. If you know beforehand what issues +one might have when setting this up, or when something is changed, or on upgrading, it's +important to describe those, too. Think of things that may go wrong and include them here. +This is important to minimize requests for support, and to avoid doc comments with +questions that you know someone might ask. + +Each scenario can be a third-level heading, e.g. `### Getting error message X`. +If you have none to add when creating a doc, leave this section in place +but commented out to help encourage others to add to it in the future. --> + [omnibus-ssl-docs]: https://docs.gitlab.com/omnibus/settings/ssl.html [omnibus-log-docs]: https://docs.gitlab.com/omnibus/settings/logs.html diff --git a/package.json b/package.json index 099d0b3d8fa..381accff23b 100644 --- a/package.json +++ b/package.json @@ -23,7 +23,7 @@ "stylelint": "node node_modules/stylelint/bin/stylelint.js app/assets/stylesheets/**/*.* ee/app/assets/stylesheets/**/*.* !**/vendors/** --custom-formatter node_modules/stylelint-error-string-formatter", "stylelint-file": "node node_modules/stylelint/bin/stylelint.js", "stylelint-create-utility-map": "node scripts/frontend/stylelint/stylelint-utility-map.js", - "test": "yarn jest && yarn karma", + "test": "node scripts/frontend/test", "webpack": "NODE_OPTIONS=\"--max-old-space-size=3584\" webpack --config config/webpack.config.js", "webpack-prod": "NODE_OPTIONS=\"--max-old-space-size=3584\" NODE_ENV=production webpack --config config/webpack.config.js" }, diff --git a/scripts/frontend/test.js b/scripts/frontend/test.js new file mode 100755 index 00000000000..dab7176f8c1 --- /dev/null +++ b/scripts/frontend/test.js @@ -0,0 +1,114 @@ +#!/usr/bin/env node + +const { spawn } = require('child_process'); +const { EOL } = require('os'); +const program = require('commander'); +const chalk = require('chalk'); + +const JEST_ROUTE = 'spec/frontend'; +const KARMA_ROUTE = 'spec/javascripts'; +const COMMON_ARGS = ['--colors']; +const JEST_ARGS = ['--passWithNoTests']; +const KARMA_ARGS = ['--no-fail-on-empty-test-suite']; +const SUCCESS_CODE = 0; + +program + .version('0.1.0') + .usage('[options] <file ...>') + .option('-p, --parallel', 'Run tests suites in parallel') + .parse(process.argv); + +const isSuccess = code => code === SUCCESS_CODE; + +const combineExitCodes = codes => { + const firstFail = codes.find(x => !isSuccess(x)); + + return firstFail === undefined ? SUCCESS_CODE : firstFail; +}; + +const skipIfFail = fn => code => (isSuccess(code) ? fn() : code); + +const endWithEOL = str => (str[str.length - 1] === '\n' ? str : `${str}${EOL}`); + +const runTests = paths => { + if (program.parallel) { + return Promise.all([runJest(paths), runKarma(paths)]).then(combineExitCodes); + } else { + return runJest(paths).then(skipIfFail(() => runKarma(paths))); + } +}; + +const spawnYarnScript = (cmd, args) => { + return new Promise((resolve, reject) => { + const proc = spawn('yarn', ['run', cmd, ...args]); + const output = data => { + const text = data + .toString() + .split(/\r?\n/g) + .map((line, idx, { length }) => + idx === length - 1 && !line ? line : `${chalk.gray(cmd)}: ${line}`, + ) + .join(EOL); + + return endWithEOL(text); + }; + + proc.stdout.on('data', data => { + process.stdout.write(output(data)); + }); + + proc.stderr.on('data', data => { + process.stderr.write(output(data)); + }); + + proc.on('close', code => { + process.stdout.write(output(`exited with code ${code}`)); + + // We resolve even on a failure code because a `reject` would cause + // Promise.all to reject immediately (without waiting for other promises) + // to finish. + resolve(code); + }); + }); +}; + +const runJest = args => { + return spawnYarnScript('jest', [...JEST_ARGS, ...COMMON_ARGS, ...toJestArgs(args)]); +}; + +const runKarma = args => { + return spawnYarnScript('karma', [...KARMA_ARGS, ...COMMON_ARGS, ...toKarmaArgs(args)]); +}; + +const replacePath = to => path => + path + .replace(JEST_ROUTE, to) + .replace(KARMA_ROUTE, to) + .replace('app/assets/javascripts', to); + +const replacePathForJest = replacePath(JEST_ROUTE); + +const replacePathForKarma = replacePath(KARMA_ROUTE); + +const toJestArgs = paths => paths.map(replacePathForJest); + +const toKarmaArgs = paths => + paths.reduce((acc, path) => acc.concat('-f', replacePathForKarma(path)), []); + +const main = paths => { + runTests(paths).then(code => { + console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); + if (isSuccess(code)) { + console.log(chalk.bgGreen(chalk.black('All tests passed :)'))); + } else { + console.log(chalk.bgRed(chalk.white(`Some tests failed :(`))); + } + console.log('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~'); + + if (!isSuccess(code)) { + process.exit(code); + } + }); +}; + +main(program.args); |