{"id":7800,"date":"2020-01-02T20:45:51","date_gmt":"2020-01-02T20:45:51","guid":{"rendered":"http:\/\/putridparrot.com\/blog\/?p=7800"},"modified":"2020-01-02T20:45:58","modified_gmt":"2020-01-02T20:45:58","slug":"pre-commit-linting-with-husky-and-lint-staged","status":"publish","type":"post","link":"https:\/\/putridparrot.com\/blog\/pre-commit-linting-with-husky-and-lint-staged\/","title":{"rendered":"Pre-commit linting with husky and lint-staged"},"content":{"rendered":"<p>You&#8217;ve got your JavaScript or TypeScript project, you&#8217;ve added eslint and set-up all the rules and you&#8217;re happily coding, committing and pushing changes to GIT, the only problem is you&#8217;re ignoring your lint results or worse still, not even running lint prior to committing changes.<\/p>\n<p>Enter, <a href=\"https:\/\/github.com\/typicode\/husky\" rel=\"noopener noreferrer\" target=\"_blank\">Husky<\/a> and <a href=\"https:\/\/github.com\/okonet\/lint-staged\" rel=\"noopener noreferrer\" target=\"_blank\">link-staged<\/a>.<\/p>\n<p><em>Note: I&#8217;m describing using Husky on a Windows machine, installation may vary depending on OS.<\/em><\/p>\n<p>Let&#8217;s add them to our project using<\/p>\n<ul>\n<li>yarn add -D husky lint-staged<\/li>\n<\/ul>\n<p>Now, within package.json (after the scripts section is as good a place as any) add the following <\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\n&quot;husky&quot;: {\r\n  &quot;hooks&quot;: {\r\n    &quot;pre-commit&quot;: &quot;lint-staged&quot;\r\n  }\r\n},\r\n&quot;lint-staged&quot;: {\r\n  &quot;*.{js,jsx,ts,tsx}&quot;: &#x5B;\r\n    &quot;eslint&quot;\r\n  ],\r\n  &quot;*.{js,jsx,ts,tsx,json}&quot;: &#x5B;\r\n    &quot;prettier --write&quot;,\r\n    &quot;git add&quot;\r\n  ]\r\n},\r\n<\/pre>\n<p><em>Note: Husky also supports it&#8217;s own configuration files .huskyrc, .huskyrc.json or .huskyrc.js<\/em><\/p>\n<p>Husky adds the ability to run applications\/code on various <a href=\"https:\/\/git-scm.com\/docs\/githooks\" rel=\"noopener noreferrer\" target=\"_blank\">GIT hooks<\/a>. The most useful, from the perspective of this post, is the pre-commit hook as we want to stop any commits until all lint failures are fixed.<\/p>\n<p>In the configuration, above, we call <em>lint-staged<\/em> when GIT commit is executed. The commit hook will run <em>husky<\/em> and <em>husky<\/em> will then run <em>lint-staged<\/em> with the previously defined configuration. <\/p>\n<p><em>Lint-staged<\/em> runs the linter (in this configuration, eslint) over our various <strong>staged<\/strong> files and also executes <em>prettier<\/em> against the same files (as well as JSON) adding these changes. <\/p>\n<p>With these two tools set-up, we no longer have the option to <em>forget<\/em> to run the linter or <em>ignore<\/em> it as it&#8217;s now part of the commit process. Ofcourse we only fail a commit on staged files, so in situations where we add these applications to an existing project we&#8217;re not force to fix all linting issues until we attempt to actually stage and commit the files.<\/p>\n<p><strong>I&#8217;ve merged or rebased and don&#8217;t want to fix everything<\/strong><\/p>\n<p>Obviously all&#8217;s great until you find old code that may need to be merged or we rebase and now have staged files which fail the lint process and we don&#8217;t want to fix them. <\/p>\n<p>In such cases, simple set the environment variable <strong>HUSKY_SKIP_HOOKS<\/strong> to true or 1 prior to running a git command, for example<\/p>\n<pre class=\"brush: java; title: ; notranslate\" title=\"\">\r\nHUSKY_SKIP_HOOKS=1 git rebase ...\r\n<\/pre>\n<p>See <a href=\"https:\/\/github.com\/typicode\/husky#skip-all-hooks-rebase\" rel=\"noopener noreferrer\" target=\"_blank\">Skip all hooks (rebase)<\/a>.<\/p>\n<p><strong>Beware the formatting infinite fix then fail circle<\/strong><\/p>\n<p>One thing to be aware of, if you&#8217;re using <em>prettier<\/em>, as per the configuration above, make sure your eslint and <em>prettier<\/em> adhere to the same rules &#8211; initially I found that eslint would complain about some formatting (I cannot recall which at the moment) so would fail the commit, upon changing the offending code to pass eslint, the <em>prettier<\/em> command ran as part of <em>lint-staged<\/em> and changed the format back, meaning it then failed the lint and would fail the commit again. <\/p>\n<p>However, running prettier and having it write changes in obviously a great way to (at least try) to enforce consistency on our code format.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>You&#8217;ve got your JavaScript or TypeScript project, you&#8217;ve added eslint and set-up all the rules and you&#8217;re happily coding, committing and pushing changes to GIT, the only problem is you&#8217;re ignoring your lint results or worse still, not even running lint prior to committing changes. Enter, Husky and link-staged. Note: I&#8217;m describing using Husky on [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_memberships_contains_paid_content":false,"footnotes":""},"categories":[278,279],"tags":[],"class_list":["post-7800","post","type-post","status-publish","format-standard","hentry","category-husky","category-lint-staged"],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/7800","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/comments?post=7800"}],"version-history":[{"count":5,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/7800\/revisions"}],"predecessor-version":[{"id":7805,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/posts\/7800\/revisions\/7805"}],"wp:attachment":[{"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/media?parent=7800"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/categories?post=7800"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/putridparrot.com\/blog\/wp-json\/wp\/v2\/tags?post=7800"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}