<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Nitzan Ohana</title>
    <description>The latest articles on DEV Community by Nitzan Ohana (@nitzano).</description>
    <link>https://dev.to/nitzano</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F420780%2F4c460a58-491a-4b8d-8c34-be7b10bfdcd1.jpg</url>
      <title>DEV Community: Nitzan Ohana</title>
      <link>https://dev.to/nitzano</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/nitzano"/>
    <language>en</language>
    <item>
      <title>Which git branch strategy are you?</title>
      <dc:creator>Nitzan Ohana</dc:creator>
      <pubDate>Wed, 25 Sep 2024 16:59:26 +0000</pubDate>
      <link>https://dev.to/nitzano/which-git-branch-strategy-are-you-2a42</link>
      <guid>https://dev.to/nitzano/which-git-branch-strategy-are-you-2a42</guid>
      <description>&lt;p&gt;TLDR - The Quiz : &lt;a href="https://git-strategy-quiz.nitzano.com" rel="noopener noreferrer"&gt;https://git-strategy-quiz.nitzano.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Branching strategies can make or break a project’s development flow. After years of working with different companies and reviewing various projects, I’ve come to realize that there’s no one-size-fits-all solution when it comes to choosing the best git strategy. Every team, project, and workflow is unique, and the right strategy can significantly impact everything—from planning and versioning to avoiding code freezes and speeding up feature deployment.&lt;/p&gt;

&lt;p&gt;That’s why I’ve created an online quiz to help teams and individuals determine which git strategy is the most suitable for their projects. I’ve included key questions that I ask every time I start or review a project.&lt;/p&gt;

&lt;p&gt;Take the quiz here:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://git-strategy-quiz.nitzano.com" rel="noopener noreferrer"&gt;https://git-strategy-quiz.nitzano.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and let me know your result in the comments. I’d love to hear what you got! 😁&lt;/p&gt;

</description>
      <category>git</category>
      <category>architecture</category>
      <category>sdlc</category>
    </item>
    <item>
      <title>Linting docker containers</title>
      <dc:creator>Nitzan Ohana</dc:creator>
      <pubDate>Sun, 19 Jul 2020 20:27:09 +0000</pubDate>
      <link>https://dev.to/nitzano/linting-docker-containers-2lo6</link>
      <guid>https://dev.to/nitzano/linting-docker-containers-2lo6</guid>
      <description>&lt;ul&gt;
&lt;li&gt;The problem&lt;/li&gt;
&lt;li&gt;Setup&lt;/li&gt;
&lt;li&gt;The general solution&lt;/li&gt;
&lt;li&gt;Husky + Lint Staged ("do-it-yourself" method)&lt;/li&gt;
&lt;li&gt;Lefthook ("all-in-one" method) 🥊&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  The problem
&lt;/h1&gt;

&lt;p&gt;When developing in a dockerized environment (for example with docker compose) you often find yourself in the following situtation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Several containers are running at once.&lt;/li&gt;
&lt;li&gt;Each container &lt;strong&gt;has it's own linter&lt;/strong&gt; (eslint, tslint, pylint, …) &lt;strong&gt;with it's own settings&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;However..you &lt;code&gt;git commit&lt;/code&gt; changes from your host/dev machine &lt;strong&gt;which doesn't have any of the linters installed&lt;/strong&gt;. &lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;In this article I'll show a quick solution so you can run every linter in the right container and always keep your code clean and pretty.&lt;/p&gt;

&lt;p&gt;We'll do that with two methods:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;🐶&lt;a href="https://github.com/typicode/husky"&gt;Husky&lt;/a&gt; +🚫💩 &lt;a href="https://github.com/okonet/lint-staged"&gt;Lint Staged&lt;/a&gt; (the "do-it-yourself" method)&lt;/li&gt;
&lt;li&gt;🥊&lt;a href="https://github.com/Arkweid/lefthook"&gt;Lefthook&lt;/a&gt; (the "all-in-one" method) (my favorite ⭐)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The final project can be found here: &lt;a href="https://github.com/nitzano/docker-linters-example"&gt;docker-linters-example&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Setup
&lt;/h1&gt;

&lt;p&gt;To demonstrate the problem I've created two sample containers:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;container1&lt;/strong&gt; (containers/container1 ) - NodeJS project using &lt;a href="https://github.com/eslint/eslint"&gt;ESlint&lt;/a&gt; linter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;container2&lt;/strong&gt; (containers/container2) - Python project with &lt;a href="https://github.com/PyCQA/pylint"&gt;Pylint&lt;/a&gt; linter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The &lt;code&gt;docker-compose.yml&lt;/code&gt; file looks something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;version&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;3.4"&lt;/span&gt;

&lt;span class="na"&gt;services&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;container1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;container1&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;container1&lt;/span&gt;    
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containers/container1&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./containers/container1/src:/app/src&lt;/span&gt;
  &lt;span class="na"&gt;container2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;container2&lt;/span&gt;
    &lt;span class="na"&gt;container_name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;container2&lt;/span&gt;
    &lt;span class="na"&gt;build&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;containers/container2&lt;/span&gt;
    &lt;span class="na"&gt;volumes&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;./containers/container2/src:/app/src&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  The general solution
&lt;/h1&gt;

&lt;p&gt;In order to run each linter in it's container will do the following:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Install a git hooks framework &lt;strong&gt;on the host&lt;/strong&gt; (your dev machine) so it will install a "pre-commit" hook that runs whenever &lt;code&gt;git commit&lt;/code&gt; is called.&lt;/li&gt;
&lt;li&gt;Configure this hook to check if the staged files &lt;strong&gt;match any of the containers source files&lt;/strong&gt; (for example &lt;code&gt;container/container/src/**/*.js&lt;/code&gt; for all the javascript files in container1 )&lt;/li&gt;
&lt;li&gt;Run the linter command with &lt;code&gt;docker run&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Additionally: mount the source directories as volumes to automatically fix files (for example with &lt;code&gt;eslint --fix&lt;/code&gt; ).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;For example for "container 1" (NodeJS) the command will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; container1/src:/app/src container1 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"yarn lint --fix &amp;lt;GIT_STAGED_FILES&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;And for container 2 (Python) it will be:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; container2/src:/app/src container2 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"pylint &amp;lt;GIT_STAGED_FILES&amp;gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Husky + Lint Staged ("do-it-yourself" method)
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--nyEX3uRW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eq65274bj78u3r2luqlx.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--nyEX3uRW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/eq65274bj78u3r2luqlx.jpg" alt="Alt Text"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We'll Start by installing the required libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-save&lt;/span&gt; husky lint-staged
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will install two libraries:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/typicode/husky"&gt;Husky&lt;/a&gt; - Will add a pre-commit hook to our .git/hooks folder.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/okonet/lint-staged"&gt;Lint staged&lt;/a&gt; - will run a linter according to matched patterns on the staged files.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Why &lt;code&gt;--no-save&lt;/code&gt;? Because we want the git hooks on the host and not include it as part of the dev/production code)&lt;/p&gt;

&lt;p&gt;Then we'll create a &lt;code&gt;.huskyrc&lt;/code&gt; configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"hooks"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"pre-commit"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"lint-staged -r -p false"&lt;/span&gt;&lt;span class="w"&gt;
   &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This will run "lint-staged" whenever we git commit files with the following options:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;-r&lt;/code&gt; - pass the file as relative to the root of the project instead of absolute ones. This means that instead of &lt;code&gt;/home/user/docker-linters-example/containers/container1/src/file1.js&lt;/code&gt; the file path passed to the command will be: &lt;code&gt;containers/containers1/src/file1.js&lt;/code&gt;  (you'll see why soon).&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-p false&lt;/code&gt; - run commands sequentially (optional: to prevent some issues)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Now for the second part: matching files to linters.&lt;br&gt;
For that we'll create a &lt;code&gt;.lintstagedrc.js&lt;/code&gt; configuration file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;path&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nx"&gt;module&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;exports&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;containers/container1/src/**/*.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;absolutePaths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;relativePaths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;absolutePaths&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;containers/container1/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`docker run --rm -v &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/containers/container1/src:/app/src container1 sh -c \"yarn lint  --fix &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;relativePaths&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\"`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;containers/container2/src/**/*.py&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;absolutePaths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;cwd&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;relativePaths&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;absolutePaths&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;map&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="nx"&gt;path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;file&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;containers/container2/&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;)&lt;/span&gt;
      &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;join&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s2"&gt;`docker run --rm -v &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;cwd&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/containers/container2/src:/app/src container2 sh -c \"pylint &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;relativePaths&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;\"`&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This configuration will match the staged files by using patterns to find to which container they belong. For pattern match will do the following &lt;br&gt;
(for example lines 4–11 for container1 files) :&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Tranform the path of every file to match the path of the container, for example &lt;code&gt;containers/container1/src/file1.js&lt;/code&gt; will become &lt;code&gt;src/file1.js&lt;/code&gt;. that is because container1's working directory is already in  &lt;code&gt;containers/container1&lt;/code&gt;  so we need to trim every path. &lt;/li&gt;
&lt;li&gt;Execute a docker run command with all the files in it, for example:
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run  - rm &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;cwd&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;/containers/container1/src:/app/src container1 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\"&lt;/span&gt;yarn lint - fix &lt;span class="k"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;relativePaths&lt;/span&gt;&lt;span class="k"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;Let's break the parts:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;code&gt;--rm&lt;/code&gt; - terminate the container after running.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;-v&lt;/code&gt; - mount the source volumes from host to container to reflect changes.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sh -c yarn lint --fix ${relativePaths}&lt;/code&gt; (the command) run the linter (in this case: ESlint)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;So for container1 the final command will look like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; /home/user/docker-linters-example/containers/container1/src:/app/src container 1 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"yarn lint --fix src/file1.js src/file2.js 
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Voila, we now get our files linted and fixed in every commit:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;husky &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pre-commit &lt;span class="o"&gt;(&lt;/span&gt;node v12.18.1&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt; &lt;span class="s1"&gt;'containers/container2/src/file1.py'&lt;/span&gt; &lt;span class="o"&gt;]&lt;/span&gt;
✔ Preparing...
⚠ Running tasks...
  ❯ Running tasks &lt;span class="k"&gt;for &lt;/span&gt;containers/container1/src/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.js
    ✖ docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; /home/user/docker-linters-example/containers/container1/src:/app/src container1 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"yarn lint  --fix src/file1.js src/file2.js"&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;FAILED]
  ❯ Running tasks &lt;span class="k"&gt;for &lt;/span&gt;containers/container2/src/&lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.py
    ✖ docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; /home/user/docker-linters-example/containers/container2/src:/app/src container2 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"pylint src/file1.py"&lt;/span&gt; &lt;span class="o"&gt;[&lt;/span&gt;FAILED]
↓ Skipped because of errors from tasks. &lt;span class="o"&gt;[&lt;/span&gt;SKIPPED]
✔ Reverting to original state because of errors...
✔ Cleaning up... 

✖ docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; /home/user/docker-linters-example/containers/container1/src:/app/src container1 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"yarn lint  --fix src/file1.js src/file2.js"&lt;/span&gt;:
error Command failed with &lt;span class="nb"&gt;exit &lt;/span&gt;code 1.
yarn run v1.22.4
&lt;span class="nv"&gt;$ &lt;/span&gt;eslint &lt;span class="nt"&gt;--fix&lt;/span&gt; src/file1.js src/file2.js

/app/src/file1.js
  1:1  warning  Unexpected console statement            no-console
  3:7  error    &lt;span class="s1"&gt;'x'&lt;/span&gt; is assigned a value but never used  no-unused-vars

/app/src/file2.js
  1:1  warning  Unexpected console statement            no-console
  3:7  error    &lt;span class="s1"&gt;'x'&lt;/span&gt; is assigned a value but never used  no-unused-vars

✖ 4 problems &lt;span class="o"&gt;(&lt;/span&gt;2 errors, 2 warnings&lt;span class="o"&gt;)&lt;/span&gt;

info Visit https://yarnpkg.com/en/docs/cli/run &lt;span class="k"&gt;for &lt;/span&gt;documentation about this command.

✖ docker run &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; /home/user/docker-linters-example/containers/container2/src:/app/src container2 sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s2"&gt;"pylint src/file1.py"&lt;/span&gt;:
&lt;span class="k"&gt;*************&lt;/span&gt; Module file1
src/file1.py:1:0: C0114: Missing module docstring &lt;span class="o"&gt;(&lt;/span&gt;missing-module-docstring&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nt"&gt;-----------------------------------&lt;/span&gt;
Your code has been rated at 0.00/10

husky &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; pre-commit hook failed &lt;span class="o"&gt;(&lt;/span&gt;add &lt;span class="nt"&gt;--no-verify&lt;/span&gt; to bypass&lt;span class="o"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h1&gt;
  
  
  Lefthook ("all-in-one" method) 🥊
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--XuTVsaK---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/suttw56czlxzq556b3j2.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--XuTVsaK---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/suttw56czlxzq556b3j2.jpg" alt="Lefthook"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;This method is my favorite because &lt;a href="https://github.com/Arkweid/lefthook"&gt;Lefthook&lt;/a&gt; includes the features of both Husky and Lint Staged. In other words it has both a git hook manager and can track the staged files from git which saves a lot of time and configuration.&lt;/p&gt;

&lt;p&gt;We'll start again by installing the required libraries:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;npm &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;--no-save&lt;/span&gt; @arkweid/lefthook
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Then we'll configure lefthook by adding a &lt;code&gt;lefthook.yml&lt;/code&gt; file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="na"&gt;pre-commit&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;parallel&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;
    &lt;span class="na"&gt;commands&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
        &lt;span class="na"&gt;lint_container1&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;containers/container1/"&lt;/span&gt;
            &lt;span class="na"&gt;glob&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.js"&lt;/span&gt;
            &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker run --rm -v ${PWD}/src:/app/src container1 sh -c "yarn lint --fix {staged_files}" &amp;amp;&amp;amp; git add {staged_files}&lt;/span&gt;
        &lt;span class="na"&gt;lint_container2&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;containers/container2/"&lt;/span&gt;
            &lt;span class="na"&gt;glob&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;*.py"&lt;/span&gt;
            &lt;span class="na"&gt;run&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;docker run --rm -v ${PWD}/src:/app/src container2 sh -c "pylint {staged_files}" &amp;amp;&amp;amp; git add {staged_files}&lt;/span&gt;

&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;This does the same as the Husky+Lint Staged method above:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Matches each container files to their correct linter configuration.&lt;/li&gt;
&lt;li&gt;Automatically transforms the paths from the host ones to the container ones (by using the &lt;code&gt;root&lt;/code&gt; property)&lt;/li&gt;
&lt;li&gt;runs  &lt;code&gt;docker run&lt;/code&gt; with the correct linter.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Result:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;Lefthook v0.7.2
RUNNING HOOKS GROUP: pre-commit

  EXECUTE &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; lint_container2
&lt;span class="k"&gt;*************&lt;/span&gt; Module file1
src/file1.py:1:0: C0114: Missing module docstring &lt;span class="o"&gt;(&lt;/span&gt;missing-module-docstring&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="nt"&gt;-----------------------------------&lt;/span&gt;
Your code has been rated at 0.00/10


  EXECUTE &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; lint_container1
yarn run v1.22.4
&lt;span class="nv"&gt;$ &lt;/span&gt;eslint &lt;span class="nt"&gt;--fix&lt;/span&gt; ./src/file1.js ./src/file2.js

/app/src/file1.js
  1:1  warning  Unexpected console statement            no-console
  3:7  error    &lt;span class="s1"&gt;'x'&lt;/span&gt; is assigned a value but never used  no-unused-vars

/app/src/file2.js
  1:1  warning  Unexpected console statement            no-console
  3:7  error    &lt;span class="s1"&gt;'x'&lt;/span&gt; is assigned a value but never used  no-unused-vars

✖ 4 problems &lt;span class="o"&gt;(&lt;/span&gt;2 errors, 2 warnings&lt;span class="o"&gt;)&lt;/span&gt;

error Command failed with &lt;span class="nb"&gt;exit &lt;/span&gt;code 1.
info Visit https://yarnpkg.com/en/docs/cli/run &lt;span class="k"&gt;for &lt;/span&gt;documentation about this command.

SUMMARY: &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="k"&gt;done in &lt;/span&gt;3.31 seconds&lt;span class="o"&gt;)&lt;/span&gt;
🥊  lint_container2
🥊  lint_container1
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



</description>
      <category>docker</category>
      <category>git</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
  </channel>
</rss>
