diff --git a/package.json b/package.json index ff1a4a40b83..66f24e49f14 100644 --- a/package.json +++ b/package.json @@ -107,6 +107,7 @@ "sass-lint": "1.12.1", "sass-loader": "7.1.0", "semver": "5.7.0", + "simple-git": "^1.112.0", "sinon": "1.17.6", "style-loader": "0.23.1", "systemjs": "0.20.19", @@ -149,11 +150,12 @@ "gui:releasePrepare": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:release", "gui:publish": "cd packages/grafana-ui/dist && npm publish --access public", "gui:release": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts gui:release -p --createVersionCommit", + "precommit": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts precommit", "cli": "ts-node --project ./scripts/cli/tsconfig.json ./scripts/cli/index.ts" }, "husky": { "hooks": { - "pre-commit": "lint-staged && grunt precommit" + "pre-commit": "lint-staged && npm run precommit" } }, "lint-staged": { diff --git a/scripts/cli/index.ts b/scripts/cli/index.ts index 49e266a31f8..de7ced12dc8 100644 --- a/scripts/cli/index.ts +++ b/scripts/cli/index.ts @@ -6,6 +6,7 @@ import { buildTask } from './tasks/grafanaui.build'; import { releaseTask } from './tasks/grafanaui.release'; import { changelogTask } from './tasks/changelog'; import { cherryPickTask } from './tasks/cherrypick'; +import { precommitTask } from './tasks/precommit'; program.option('-d, --depreciate ', 'Inform about npm script deprecation', v => v.split(',')); @@ -64,6 +65,13 @@ program await execTask(cherryPickTask)({}); }); +program + .command('precommit') + .description('Executes checks') + .action(async cmd => { + await execTask(precommitTask)({}); + }); + program.parse(process.argv); if (program.depreciate && program.depreciate.length === 2) { diff --git a/scripts/cli/tasks/precommit.ts b/scripts/cli/tasks/precommit.ts new file mode 100644 index 00000000000..b759aa414f2 --- /dev/null +++ b/scripts/cli/tasks/precommit.ts @@ -0,0 +1,81 @@ +import { Task, TaskRunner } from './task'; +import chalk from 'chalk'; +import get from 'lodash/get'; +import flatten from 'lodash/flatten'; +import execa = require('execa'); +const simpleGit = require('simple-git/promise')(process.cwd()); + +interface PrecommitOptions {} + +const tasks = { + lint: { + sass: ['newer:sasslint'], + core: ['newer:exec:tslintRoot'], + gui: ['newer:exec:tslintPackages'], + }, + typecheck: { + core: ['newer:exec:typecheckRoot'], + gui: ['newer:exec:typecheckPackages'], + }, + test: { + lint: { + ts: ['no-only-tests'], + go: ['no-focus-convey-tests'], + }, + }, +}; + +const precommitRunner: TaskRunner = async () => { + const status = await simpleGit.status(); + const sassFiles = status.files.filter( + file => (file.path as string).match(/^[a-zA-Z0-9\_\-\/]+(\.scss)$/g) || file.path.indexOf('.sass-lint.yml') > -1 + ); + + const tsFiles = status.files.filter(file => (file.path as string).match(/^[a-zA-Z0-9\_\-\/]+(\.(ts|tsx))$/g)); + const testFiles = status.files.filter(file => (file.path as string).match(/^[a-zA-Z0-9\_\-\/]+(\.test.(ts|tsx))$/g)); + const goTestFiles = status.files.filter(file => (file.path as string).match(/^[a-zA-Z0-9\_\-\/]+(\_test.go)$/g)); + const grafanaUiFiles = tsFiles.filter(file => (file.path as string).indexOf('grafana-ui') > -1); + + const grafanaUIFilesChangedOnly = tsFiles.length > 0 && tsFiles.length - grafanaUiFiles.length === 0; + const coreFilesChangedOnly = tsFiles.length > 0 && grafanaUiFiles.length === 0; + + const taskPaths = []; + + if (sassFiles.length > 0) { + taskPaths.push('lint.sass'); + } + + if (testFiles.length) { + taskPaths.push('test.lint.ts'); + } + + if (goTestFiles.length) { + taskPaths.push('test.lint.go'); + } + + if (tsFiles.length > 0) { + if (grafanaUIFilesChangedOnly) { + taskPaths.push('lint.gui', 'typecheck.core', 'typecheck.gui'); + } else if (coreFilesChangedOnly) { + taskPaths.push('lint.core', 'typecheck.core'); + } else { + taskPaths.push('lint.core', 'lint.gui', 'typecheck.core', 'typecheck.gui'); + } + } + + const gruntTasks = flatten(taskPaths.map(path => get(tasks, path))); + if (gruntTasks.length > 0) { + console.log(chalk.yellow(`Precommit checks: ${taskPaths.join(', ')}`)); + const task = execa('grunt', gruntTasks); + // @ts-ignore + const stream = task.stdout; + stream.pipe(process.stdout); + return task; + } + console.log(chalk.yellow('Skipping precommit checks, not front-end changes detected')); + return; +}; + +export const precommitTask = new Task(); +precommitTask.setName('Precommit task'); +precommitTask.setRunner(precommitRunner); diff --git a/scripts/cli/tasks/task.ts b/scripts/cli/tasks/task.ts index d88860b7017..cc7d77a0664 100644 --- a/scripts/cli/tasks/task.ts +++ b/scripts/cli/tasks/task.ts @@ -1,8 +1,8 @@ -export type TaskRunner = (options: T) => Promise; +export type TaskRunner = (options: T) => Promise; export class Task { name: string; - runner: (options: TOptions) => Promise; + runner: (options: TOptions) => Promise; options: TOptions; setName = name => { diff --git a/scripts/grunt/default_task.js b/scripts/grunt/default_task.js index 7619ef8601c..95a2522ccfc 100644 --- a/scripts/grunt/default_task.js +++ b/scripts/grunt/default_task.js @@ -31,15 +31,6 @@ module.exports = function(grunt) { 'newer:exec:typecheckRoot' ]); - // prettier-ignore - grunt.registerTask('precommit', [ - 'newer:sasslint', - 'typecheck', - 'tslint', - 'no-only-tests', - 'no-focus-convey-tests' - ]); - grunt.registerTask('no-only-tests', function() { var files = grunt.file.expand( 'public/**/*@(_specs|.test).@(ts|js|tsx|jsx)', @@ -65,4 +56,3 @@ module.exports = function(grunt) { }); } }; - diff --git a/yarn.lock b/yarn.lock index 8cc31a6880e..a07cbe81a87 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6074,7 +6074,7 @@ debug@^4.0.1, debug@^4.1.0, debug@^4.1.1: dependencies: ms "^2.1.1" -debuglog@*, debuglog@^1.0.1: +debuglog@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= @@ -8903,7 +8903,7 @@ import-local@^2.0.0: pkg-dir "^3.0.0" resolve-cwd "^2.0.0" -imurmurhash@*, imurmurhash@^0.1.4: +imurmurhash@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= @@ -10434,7 +10434,7 @@ libnpm@^2.0.1: read-package-json "^2.0.13" stringify-package "^1.0.0" -libnpmaccess@*, libnpmaccess@^3.0.1: +libnpmaccess@^3.0.1: version "3.0.1" resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-3.0.1.tgz#5b3a9de621f293d425191aa2e779102f84167fa8" integrity sha512-RlZ7PNarCBt+XbnP7R6PoVgOq9t+kou5rvhaInoNibhPO7eMlRfS0B8yjatgn2yaHIwWNyoJDolC/6Lc5L/IQA== @@ -10463,7 +10463,7 @@ libnpmhook@^5.0.2: get-stream "^4.0.0" npm-registry-fetch "^3.8.0" -libnpmorg@*, libnpmorg@^1.0.0: +libnpmorg@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/libnpmorg/-/libnpmorg-1.0.0.tgz#979b868c48ba28c5820e3bb9d9e73c883c16a232" integrity sha512-o+4eVJBoDGMgRwh2lJY0a8pRV2c/tQM/SxlqXezjcAg26Qe9jigYVs+Xk0vvlYDWCDhP0g74J8UwWeAgsB7gGw== @@ -10488,7 +10488,7 @@ libnpmpublish@^1.1.0: semver "^5.5.1" ssri "^6.0.1" -libnpmsearch@*, libnpmsearch@^2.0.0: +libnpmsearch@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/libnpmsearch/-/libnpmsearch-2.0.0.tgz#de05af47ada81554a5f64276a69599070d4a5685" integrity sha512-vd+JWbTGzOSfiOc+72MU6y7WqmBXn49egCCrIXp27iE/88bX8EpG64ST1blWQI1bSMUr9l1AKPMVsqa2tS5KWA== @@ -10497,7 +10497,7 @@ libnpmsearch@*, libnpmsearch@^2.0.0: get-stream "^4.0.0" npm-registry-fetch "^3.8.0" -libnpmteam@*, libnpmteam@^1.0.1: +libnpmteam@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/libnpmteam/-/libnpmteam-1.0.1.tgz#ff704b1b6c06ea674b3b1101ac3e305f5114f213" integrity sha512-gDdrflKFCX7TNwOMX1snWojCoDE5LoRWcfOC0C/fqF7mBq8Uz9zWAX4B2RllYETNO7pBupBaSyBDkTAC15cAMg== @@ -10696,11 +10696,6 @@ lodash-es@^4.17.11: resolved "https://registry.yarnpkg.com/lodash-es/-/lodash-es-4.17.11.tgz#145ab4a7ac5c5e52a3531fb4f310255a152b4be0" integrity sha512-DHb1ub+rMjjrxqlB3H56/6MXtm1lSksDp2rA2cNWjG8mlDUYFhUj3Di2Zn5IwSU87xLv8tNIQ7sSwE/YOX/D/Q== -lodash._baseindexof@*: - version "3.1.0" - resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c" - integrity sha1-/lK1OhxnYeQmGNZU5KJXie1hgiw= - lodash._baseuniq@~4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8" @@ -10709,29 +10704,12 @@ lodash._baseuniq@~4.6.0: lodash._createset "~4.0.0" lodash._root "~3.0.0" -lodash._bindcallback@*: - version "3.0.1" - resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e" - integrity sha1-5THCdkTPi1epnhftlbNcdIeJOS4= - -lodash._cacheindexof@*: - version "3.0.2" - resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92" - integrity sha1-PcaayCSY0u5ePOVgkbr9Ktx73pI= - -lodash._createcache@*: - version "3.1.2" - resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093" - integrity sha1-VtagZAF2JeeevKa4AY4XRAvc8JM= - dependencies: - lodash._getnative "^3.0.0" - lodash._createset@~4.0.0: version "4.0.3" resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26" integrity sha1-D0ZZ+7CddRlPqeK4imZE02PJ/iY= -lodash._getnative@*, lodash._getnative@^3.0.0: +lodash._getnative@^3.0.0: version "3.9.1" resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5" integrity sha1-VwvH3t5G1hzc3mh9ZdPuy6o6r/U= @@ -10830,11 +10808,6 @@ lodash.pick@^4.4.0: resolved "https://registry.yarnpkg.com/lodash.pick/-/lodash.pick-4.4.0.tgz#52f05610fff9ded422611441ed1fc123a03001b3" integrity sha1-UvBWEP/53tQiYRRB7R/BI6AwAbM= -lodash.restparam@*: - version "3.6.1" - resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805" - integrity sha1-k2pOMJ7zMKdkXtQUWYbIWuWyCAU= - lodash.some@^4.6.0: version "4.6.0" resolved "https://registry.yarnpkg.com/lodash.some/-/lodash.some-4.6.0.tgz#1bb9f314ef6b8baded13b549169b2a945eb68e4d" @@ -11999,7 +11972,7 @@ npm-pick-manifest@^2.2.3: npm-package-arg "^6.0.0" semver "^5.4.1" -npm-profile@*, npm-profile@^4.0.1: +npm-profile@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/npm-profile/-/npm-profile-4.0.1.tgz#d350f7a5e6b60691c7168fbb8392c3603583f5aa" integrity sha512-NQ1I/1Q7YRtHZXkcuU1/IyHeLy6pd+ScKg4+DQHdfsm769TGq6HPrkbuNJVJS4zwE+0mvvmeULzQdWn2L2EsVA== @@ -14481,7 +14454,7 @@ readable-stream@~1.1.10: isarray "0.0.1" string_decoder "~0.10.x" -readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0: +readdir-scoped-modules@^1.0.0: version "1.0.2" resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747" integrity sha1-n6+jfShr5dksuuve4DDcm19AZ0c= @@ -15619,7 +15592,7 @@ simple-get@^2.7.0: once "^1.3.1" simple-concat "^1.0.0" -simple-git@^1.85.0: +simple-git@^1.112.0, simple-git@^1.85.0: version "1.112.0" resolved "https://registry.yarnpkg.com/simple-git/-/simple-git-1.112.0.tgz#2aec1b124c3705adf6baf977b663a0632f50267f" integrity sha512-3vY0SW+RkO+ElWH07n/PQuKmuNLZSz3VAkxKMr3UMm/QnaSnYFjg3nqT8V6a0QCcUFpkyAWVsruQt4oSIIzPXw==