<?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: Douglas Lise</title>
    <description>The latest articles on DEV Community by Douglas Lise (@douglaslise).</description>
    <link>https://dev.to/douglaslise</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%2F14849%2F622d145d-e0a5-4e71-9bf1-a1f81b016541.jpeg</url>
      <title>DEV Community: Douglas Lise</title>
      <link>https://dev.to/douglaslise</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/douglaslise"/>
    <language>en</language>
    <item>
      <title>Como adicionar análise sintática de código ruby em uma aplicação legada?</title>
      <dc:creator>Douglas Lise</dc:creator>
      <pubDate>Wed, 04 Mar 2020 23:39:27 +0000</pubDate>
      <link>https://dev.to/douglaslise/como-adicionar-analise-sintatica-de-codigo-ruby-em-uma-aplicacao-legada-39ed</link>
      <guid>https://dev.to/douglaslise/como-adicionar-analise-sintatica-de-codigo-ruby-em-uma-aplicacao-legada-39ed</guid>
      <description>&lt;p&gt;Como é conhecido na comunidade ruby, &lt;a href="https://docs.rubocop.org/"&gt;Rubocop&lt;/a&gt; é a ferramenta mais usada para análise estática de código.&lt;/p&gt;

&lt;p&gt;Ele já vem com muitas regras padrões, o que é muito útil para novos projetos, dessa forma você pode seguir a maioria dos padrões e apenas personalizar alguns deles.&lt;/p&gt;

&lt;p&gt;Mas como proceder em projetos antigos ou maiores, com muitos arquivos e com muitos problemas?&lt;/p&gt;

&lt;p&gt;A gem Rubocop vem com um formatador automático que pode corrigir muitos problemas automaticamente em nosso código.&lt;/p&gt;

&lt;p&gt;Além disso, ele pode criar um arquivo de configuração TODO que ignora todos os problemas já presentes, arquivo por arquivo. Assim, podemos começar a usar o rubocop apenas para novos arquivos ou novos problemas nos arquivos existentes e corrigir cada problema de forma incremental.&lt;/p&gt;

&lt;p&gt;A recomendação é corrigir todos os problemas possíveis automaticamente e manter os outros ignorados, a serem corrigidos em uma etapa futura.&lt;/p&gt;

&lt;p&gt;Você pode começar adicionando a gem ao Gemfile (ou simplesmente instalando-a, mas é recomendável mantê-la no Gemfile).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; bundle add rubocop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Com isso, você pode simplesmente executar o &lt;code&gt;rubocop&lt;/code&gt; e todos os problemas serão mostrados. Como este exemplo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop
...
test/test_helper.rb:5:7: C: Style/ClassAndModuleChildren: Use nested module/class definitions instead of compact style.
class ActiveSupport::TestCase
      ^^^^^^^^^^^^^^^^^^^^^^^
test/test_helper.rb:6:81: C: Metrics/LineLength: Line is too long. [82/80]
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
                                                                                ^^

135 files inspected, 1659 offenses detected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A partir de agora podemos seguir por duas estratégias diferentes:&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Corrigindo todos os problemas em uma única vez
&lt;/h2&gt;

&lt;p&gt;A primeira estratégia é corrigir todos os problemas de uma única vez. Para isso, basta executar &lt;code&gt;rubocop --auto-correct&lt;/code&gt; e todos os problemas &lt;em&gt;corrigíveis&lt;/em&gt; são corrigidos e mostrados com o status " [Corrected] ".&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop --auto-correct
...
ENV['RAILS_ENV'] ||= 'test'
^
test/application_system_test_case.rb:1:1: C: [Corrected] Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
require "test_helper"
^

135 files inspected, 1848 offenses detected, 1485 offenses corrected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Na próxima execução, apenas os problemas restantes serão mostrados.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop
...
135 files inspected, 363 offenses detected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Agora podemos ignorar todos estes erros rodando o rubocop com a opção &lt;code&gt;--auto-gen-config&lt;/code&gt;. Isso criará dois arquivos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.rubocop_todo.yml&lt;/code&gt;: Este arquivo contém regras para ignorar todos os problemas atuais.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.rubocop.yml&lt;/code&gt;: O principal arquivo de configuração. Inicialmente apenas herdando / incluindo o arquivo TODO.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop --auto-gen-config
...
135 files inspected, 133 offenses detected
Created .rubocop_todo.yml.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;A próxima execução não deve retornar problemas, porque todos são ignorados em &lt;code&gt;.rubocop_todo.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop
...
135 files inspected, no offenses detected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Agora você precisa apenas commitar todas as alterações e, opcionalmente, adicionar uma etapa no pipeline do CI para executar o rubocop e verificar seus arquivos de origem.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Corrigindo um problema de cada vez
&lt;/h2&gt;

&lt;p&gt;A outra estratégia é fazer isso de forma incremental, usando um script, para separar cada correção de problema em um commit git diferente. Isso ajudará em uma futura identificação de alterações e o motivo pelo qual ela ocorreu.&lt;br&gt;
Para fazer isso, basta executar este script e ele irá aplicar e commitar cada problema em um commit separado.&lt;/p&gt;

&lt;p&gt;É importante criar esse script em um caminho ignorado pelo git, como &lt;code&gt;tmp/script.rb&lt;/code&gt; por exemplo. Após criar o arquivo de script, basta chamá-lo executando &lt;code&gt;ruby tmp/script.rb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tmp/script.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"yaml"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"rubocop"&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Criando configuração..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rubocop --auto-gen-config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rm .rubocop.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# OR git checkout .rubocop.yml if you want to start with some config&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Lendo a configuração de TODO para obter todos os problemas..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".rubocop_todo.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rm .rubocop_todo.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_cop_settings&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Corrigindo &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"RuboCop::Cop::&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&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="s2"&gt;"::"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;support_autocorrect?&lt;/span&gt;
    &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`rubocop --auto-correct --force-default-config --only &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; --format files`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"git add &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"git commit -m &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Correção automática do Rubocop para &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; \
            --author &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Rubocop Auto Correct &amp;lt;rubocop@rubocop&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  Não suporta auto-correção"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Gerando o arquivo TODO final com problemas incorrigíveis..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rubocop --auto-gen-config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Finalizado"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Poderá levar alguns minutos para ser executado, dependendo do número e tamanho dos seus arquivos fonte.&lt;/p&gt;

&lt;p&gt;O Rubocop foi projetado para ser seguro, mas algumas correções automáticas podem causar algum comportamento indesejado, por isso é importante ter uma boa cobertura de testes. É possível executar os testes unitários em cada iteração deste script ou apenas executá-los no final do processo. Nesse caso, se ocorrer um erro, você poderá usar &lt;code&gt;git bisect&lt;/code&gt; para descobrir qual problema introduziu o erro.&lt;/p&gt;

&lt;p&gt;No final, o script gera commits como os abaixo:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; git log --oneline
fad06ac (HEAD -&amp;gt; rubocop) Correção automática do Rubocop para Style/WordArray
22aca61 Correção automática do Rubocop para Style/ClassCheck
06b12a2 Correção automática do Rubocop para Style/BracesAroundHashParameters
6dcace8 Correção automática do Rubocop para Style/BlockDelimiters
a504890 Correção automática do Rubocop para Style/BlockComments
1fae73b Correção automática do Rubocop para Naming/RescuedExceptionsVariableName
10802ca Correção automática do Rubocop para Lint/UnusedMethodArgument
bd11ffc Correção automática do Rubocop para Lint/UnusedBlockArgument
b8e098d Correção automática do Rubocop para Layout/TrailingBlankLines
4cabbd7 Correção automática do Rubocop para Layout/Tab
f29e766 Correção automática do Rubocop para Layout/SpaceInsidePercentLiteralDelimiters
b451890 Correção automática do Rubocop para Layout/SpaceInsideHashLiteralBraces
ee9eae6 Correção automática do Rubocop para Layout/SpaceInsideBlockBraces
f6611fd Correção automática do Rubocop para Layout/SpaceInsideArrayLiteralBrackets
f858545 Correção automática do Rubocop para Layout/SpaceInLambdaLiteral
3aeed2e Correção automática do Rubocop para Layout/SpaceBeforeComment
8b40371 Correção automática do Rubocop para Layout/SpaceBeforeBlockBraces
444f7ae Correção automática do Rubocop para Layout/SpaceAroundEqualsInParameterDefault
42d4e69 Correção automática do Rubocop para Layout/SpaceAfterComma
1acc003 Correção automática do Rubocop para Layout/SpaceAfterColon
28ed714 Correção automática do Rubocop para Layout/MultilineOperationIndentation
3e08ad7 Correção automática do Rubocop para Layout/MultilineMethodCallIndentation
f4611e5 Correção automática do Rubocop para Layout/MultilineMethodCallBraceLayout
6cc68b6 Correção automática do Rubocop para Layout/MultilineHashBraceLayout
9f66fe9 Correção automática do Rubocop para Layout/LeadingCommentSpace
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Independentemente da estratégia utilizada, é recomendável resolver todos os problemas que permaneceram no arquivo TODO e, incrementalmente, mover todos os ignorados que realmente precisam ser ignorados para arquivo principal &lt;code&gt;rubocop.yml&lt;/code&gt;. Isso garantirá que você continue melhorando seu código ou, pelo menos, mantendo sua qualidade.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>code</category>
      <category>staticanalysis</category>
      <category>rubocop</category>
    </item>
    <item>
      <title>How to migrate all your Git repositores to a new computer?</title>
      <dc:creator>Douglas Lise</dc:creator>
      <pubDate>Wed, 15 Jan 2020 02:11:31 +0000</pubDate>
      <link>https://dev.to/douglaslise/how-to-migrate-all-your-git-repositores-to-a-new-computer-2c72</link>
      <guid>https://dev.to/douglaslise/how-to-migrate-all-your-git-repositores-to-a-new-computer-2c72</guid>
      <description>&lt;p&gt;Have you ever needed to change from an old computer to a new one and needed to manually clone all the Git repositories?&lt;/p&gt;

&lt;p&gt;The below script keeps your folder structure and migrates all repositories to a new computer.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;dirs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;find &lt;span class="nb"&gt;.&lt;/span&gt; &lt;span class="nt"&gt;-name&lt;/span&gt; &lt;span class="s1"&gt;'.git'&lt;/span&gt; &lt;span class="nt"&gt;-type&lt;/span&gt; d | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/\/\.git//'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="nb"&gt;dir &lt;/span&gt;&lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="nv"&gt;$dirs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
  &lt;/span&gt;&lt;span class="nv"&gt;GIT_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$dir&lt;/span&gt;/.git

  &lt;span class="c"&gt;# Creates the folder structure&lt;/span&gt;
  &lt;span class="nb"&gt;echo mkdir&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;# Clones the repository in the same folder&lt;/span&gt;
  &lt;span class="nb"&gt;echo &lt;/span&gt;git clone &lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nt"&gt;--git-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt; remote get-url origin&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="nv"&gt;$dir&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c"&gt;# Re-adds other remotes&lt;/span&gt;
  &lt;span class="k"&gt;for &lt;/span&gt;r &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nt"&gt;--git-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt; remote | &lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-v&lt;/span&gt; origin&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;do
    &lt;/span&gt;&lt;span class="nb"&gt;echo &lt;/span&gt;git &lt;span class="nt"&gt;--git-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt; remote add &lt;span class="nv"&gt;$r&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;git &lt;span class="nt"&gt;--git-dir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$GIT_DIR&lt;/span&gt; remote get-url &lt;span class="nv"&gt;$r&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;done

  &lt;/span&gt;&lt;span class="nb"&gt;echo
&lt;/span&gt;&lt;span class="k"&gt;done&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; clone-all.sh
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;You just need to paste it into a shell session at the base folder where all your repositories are stored. The script creates a file named &lt;code&gt;clone-all.sh&lt;/code&gt;. Next, you just need to copy and run this file in the new computer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Script explanation
&lt;/h2&gt;

&lt;p&gt;The script initially finds all sub-folders that contain a &lt;code&gt;.git&lt;/code&gt; folder, which denotes it as a Git repository. From this list it starts to output commands that will be executed in the new computer.&lt;/p&gt;

&lt;p&gt;The output commands (for each folder) are these:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A command to create the folder, keeping the same structure;&lt;/li&gt;
&lt;li&gt;A command to clone the repository, to the same folder name, using the &lt;code&gt;origin&lt;/code&gt; remote;&lt;/li&gt;
&lt;li&gt;A command to add the other remotes (different than &lt;code&gt;origin&lt;/code&gt;) to the newly cloned repository.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Example
&lt;/h2&gt;

&lt;p&gt;In the old computer, before run the script, the folder structure was this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  &lt;span class="nb"&gt;pwd&lt;/span&gt;
/home/douglas/code

➜  tree &lt;span class="nt"&gt;-L&lt;/span&gt; 2
&lt;span class="nb"&gt;.&lt;/span&gt;
├── create-clone-script.sh
├── other
│   ├── audited_views
│   ├── bitmovin-ruby
│   ├── cucumber-ruby
│   ├── devise-i18n
│   ├── douglaslise.github.io
│   ├── gitlab-ci-monitor
│   ├── rubocop
│   ├── sendgrid-ruby
│   └── summernote
└── private
    ├── ping-monitor
    └── qd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;So I pasted the script in the shell and it generated this file &lt;code&gt;clone-all.sh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  cat clone-all.sh           
mkdir -p ./other/bitmovin-ruby
git clone git@github.com:bitmovin/bitmovin-ruby.git ./other/bitmovin-ruby
git --git-dir=./other/bitmovin-ruby/.git remote add fork git@github.com:douglaslise/bitmovin-ruby.git

mkdir -p ./other/audited_views
git clone git@github.com:douglaslise/audited_views.git ./other/audited_views

mkdir -p ./other/cucumber-ruby
git clone git@github.com:cucumber/cucumber-ruby.git ./other/cucumber-ruby

mkdir -p ./other/rubocop
git clone git@github.com:rubocop-hq/rubocop ./other/rubocop

mkdir -p ./other/gitlab-ci-monitor
git clone git@github.com:globocom/gitlab-ci-monitor.git ./other/gitlab-ci-monitor
git --git-dir=./other/gitlab-ci-monitor/.git remote add fork git@github.com:douglaslise/gitlab-ci-monitor.git

mkdir -p ./other/summernote
git clone git@github.com:summernote/summernote.git ./other/summernote

mkdir -p ./other/devise-i18n
git clone git@github.com:tigrish/devise-i18n.git ./other/devise-i18n
git --git-dir=./other/devise-i18n/.git remote add fork git@github.com:douglaslise/devise-i18n.git

mkdir -p ./other/douglaslise.github.io
git clone git@github.com:douglaslise/douglaslise.github.io.git ./other/douglaslise.github.io

mkdir -p ./other/sendgrid-ruby
git clone git@github.com:sendgrid/sendgrid-ruby.git ./other/sendgrid-ruby
git --git-dir=./other/sendgrid-ruby/.git remote add fork git@github.com:douglaslise/sendgrid-ruby.git

mkdir -p ./private/ping-monitor
git clone ssh://hg@bitbucket.org/douglaslise/ping-monitor ./private/ping-monitor
git --git-dir=./private/ping-monitor/.git remote add heroku https://git.heroku.com/pingmonitor.git

mkdir -p ./private/qd
git clone ssh://hg@bitbucket.org/douglaslise/qd ./private/qd
➜   
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Next, I copied the generated file to the new computer and executed it in the base folder where I wanted to clone all the repositories:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight shell"&gt;&lt;code&gt;➜  &lt;span class="nb"&gt;pwd&lt;/span&gt;
/home/douglas-new/code

➜  &lt;span class="nb"&gt;ls
&lt;/span&gt;clone-all.sh

➜  sh clone-all.sh
Cloning into &lt;span class="s1"&gt;'./other/bitmovin-ruby'&lt;/span&gt;...
remote: Enumerating objects: 56, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;56/56&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;43/43&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 1707 &lt;span class="o"&gt;(&lt;/span&gt;delta 21&lt;span class="o"&gt;)&lt;/span&gt;, reused 33 &lt;span class="o"&gt;(&lt;/span&gt;delta 10&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 1651
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;1707/1707&lt;span class="o"&gt;)&lt;/span&gt;, 245.62 KiB | 1.00 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;1051/1051&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/audited_views'&lt;/span&gt;...
remote: Enumerating objects: 314, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 314 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 314
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;314/314&lt;span class="o"&gt;)&lt;/span&gt;, 48.93 KiB | 331.00 KiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;81/81&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/cucumber-ruby'&lt;/span&gt;...
remote: Enumerating objects: 371, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;371/371&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;203/203&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 58832 &lt;span class="o"&gt;(&lt;/span&gt;delta 227&lt;span class="o"&gt;)&lt;/span&gt;, reused 264 &lt;span class="o"&gt;(&lt;/span&gt;delta 163&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 58461
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;58832/58832&lt;span class="o"&gt;)&lt;/span&gt;, 11.76 MiB | 4.73 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;40075/40075&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/rubocop'&lt;/span&gt;...
remote: Enumerating objects: 11, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;11/11&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;11/11&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 90142 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, reused 2 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 90131
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;90142/90142&lt;span class="o"&gt;)&lt;/span&gt;, 29.81 MiB | 4.98 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;68283/68283&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/gitlab-ci-monitor'&lt;/span&gt;...
remote: Enumerating objects: 14, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;14/14&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;13/13&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 390 &lt;span class="o"&gt;(&lt;/span&gt;delta 3&lt;span class="o"&gt;)&lt;/span&gt;, reused 3 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 376
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;390/390&lt;span class="o"&gt;)&lt;/span&gt;, 471.38 KiB | 1.36 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;210/210&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/summernote'&lt;/span&gt;...
remote: Enumerating objects: 41, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;41/41&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;36/36&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 21101 &lt;span class="o"&gt;(&lt;/span&gt;delta 21&lt;span class="o"&gt;)&lt;/span&gt;, reused 11 &lt;span class="o"&gt;(&lt;/span&gt;delta 5&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 21060
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;21101/21101&lt;span class="o"&gt;)&lt;/span&gt;, 13.13 MiB | 4.58 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;13576/13576&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/devise-i18n'&lt;/span&gt;...
remote: Enumerating objects: 114, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;114/114&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;79/79&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 4852 &lt;span class="o"&gt;(&lt;/span&gt;delta 45&lt;span class="o"&gt;)&lt;/span&gt;, reused 56 &lt;span class="o"&gt;(&lt;/span&gt;delta 19&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 4738
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;4852/4852&lt;span class="o"&gt;)&lt;/span&gt;, 1.33 MiB | 2.81 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;2928/2928&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/douglaslise.github.io'&lt;/span&gt;...
remote: Enumerating objects: 463, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 463 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, reused 0 &lt;span class="o"&gt;(&lt;/span&gt;delta 0&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 463
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;463/463&lt;span class="o"&gt;)&lt;/span&gt;, 4.46 MiB | 3.07 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;92/92&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./other/sendgrid-ruby'&lt;/span&gt;...
remote: Enumerating objects: 23, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Counting objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;23/23&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;17/17&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 2861 &lt;span class="o"&gt;(&lt;/span&gt;delta 7&lt;span class="o"&gt;)&lt;/span&gt;, reused 14 &lt;span class="o"&gt;(&lt;/span&gt;delta 4&lt;span class="o"&gt;)&lt;/span&gt;, pack-reused 2838
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;2861/2861&lt;span class="o"&gt;)&lt;/span&gt;, 680.79 KiB | 1.60 MiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;1313/1313&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./private/ping-monitor'&lt;/span&gt;...
remote: Counting objects: 490, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;436/436&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 490 &lt;span class="o"&gt;(&lt;/span&gt;delta 256&lt;span class="o"&gt;)&lt;/span&gt;, reused 75 &lt;span class="o"&gt;(&lt;/span&gt;delta 25&lt;span class="o"&gt;)&lt;/span&gt;
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;490/490&lt;span class="o"&gt;)&lt;/span&gt;, 72.60 KiB | 352.00 KiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;256/256&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;

Cloning into &lt;span class="s1"&gt;'./private/qd'&lt;/span&gt;...
remote: Counting objects: 632, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Compressing objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;418/418&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
remote: Total 632 &lt;span class="o"&gt;(&lt;/span&gt;delta 288&lt;span class="o"&gt;)&lt;/span&gt;, reused 332 &lt;span class="o"&gt;(&lt;/span&gt;delta 128&lt;span class="o"&gt;)&lt;/span&gt;
Receiving objects: 100% &lt;span class="o"&gt;(&lt;/span&gt;632/632&lt;span class="o"&gt;)&lt;/span&gt;, 151.00 KiB | 322.00 KiB/s, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
Resolving deltas: 100% &lt;span class="o"&gt;(&lt;/span&gt;288/288&lt;span class="o"&gt;)&lt;/span&gt;, &lt;span class="k"&gt;done&lt;/span&gt;&lt;span class="nb"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now we can see the newly created structure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;➜  tree -L 2
.
├── clone-all.sh
├── other
│   ├── audited_views
│   ├── bitmovin-ruby
│   ├── cucumber-ruby
│   ├── devise-i18n
│   ├── douglaslise.github.io
│   ├── gitlab-ci-monitor
│   ├── rubocop
│   ├── sendgrid-ruby
│   └── summernote
└── private
    ├── ping-monitor
    └── qd
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;This could be used to clone all your projects just by copying a unique, small file, without the needing to copy all the files and folders.&lt;/p&gt;

&lt;p&gt;If you have suggestions, please let me know in the comments.&lt;/p&gt;

&lt;p&gt;Thanks.&lt;/p&gt;

</description>
      <category>git</category>
      <category>bash</category>
    </item>
    <item>
      <title>How to start using ruby syntatic analysis in a legacy application? </title>
      <dc:creator>Douglas Lise</dc:creator>
      <pubDate>Wed, 14 Aug 2019 00:25:47 +0000</pubDate>
      <link>https://dev.to/douglaslise/how-to-start-using-ruby-syntatic-analysis-in-a-legacy-application-22j0</link>
      <guid>https://dev.to/douglaslise/how-to-start-using-ruby-syntatic-analysis-in-a-legacy-application-22j0</guid>
      <description>&lt;p&gt;As known in ruby community, &lt;a href="https://docs.rubocop.org/"&gt;Rubocop&lt;/a&gt; is the most used tool for static code analysis. &lt;/p&gt;

&lt;p&gt;It comes with a lot of default rules, what is very useful for new projects, when you could follow the most of defaults and just customize some of them.&lt;/p&gt;

&lt;p&gt;But how to proceed in legacy or bigger projects, that have a lot of files already written and potentially having many issues?&lt;/p&gt;

&lt;p&gt;Rubocop gem comes with an auto-formatter that could fix a lot of issues automatically in our code. &lt;/p&gt;

&lt;p&gt;Additionally, it could create a TODO config file that ignores all the issues already present, file by file. So we can start using rubocop just for new files, or new issues in existing files, and incrementally fix issue by issue.&lt;/p&gt;

&lt;p&gt;The recommendation is to fix all possible issues automatically and keep others as ignored, to be fixed in a future step.&lt;/p&gt;

&lt;p&gt;You can start by adding the gem to Gemfile (or simply installing it, but it is recommended to keep it in Gemfile).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; bundle add rubocop
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;With this you could just run &lt;code&gt;rubocop&lt;/code&gt; and all issues will be shown. Like this example:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop
...
test/test_helper.rb:5:7: C: Style/ClassAndModuleChildren: Use nested module/class definitions instead of compact style.
class ActiveSupport::TestCase
      ^^^^^^^^^^^^^^^^^^^^^^^
test/test_helper.rb:6:81: C: Metrics/LineLength: Line is too long. [82/80]
  # Setup all fixtures in test/fixtures/*.yml for all tests in alphabetical order.
                                                                                ^^

135 files inspected, 1659 offenses detected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now there are two strategies to go ahead.&lt;/p&gt;

&lt;h2&gt;
  
  
  1. Fix all issues in a single batch
&lt;/h2&gt;

&lt;p&gt;The first strategy is to fix all the issues in a single batch. To do this just run &lt;code&gt;rubocop --auto-correct&lt;/code&gt; and all &lt;em&gt;fixable&lt;/em&gt; issues are fixed and shown with the "[Corrected]" status.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop --auto-correct
...
ENV['RAILS_ENV'] ||= 'test'
^
test/application_system_test_case.rb:1:1: C: [Corrected] Style/FrozenStringLiteralComment: Missing magic comment # frozen_string_literal: true.
require "test_helper"
^

135 files inspected, 1848 offenses detected, 1485 offenses corrected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;In the next run just the remaining issues are shown.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop
...
135 files inspected, 363 offenses detected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;We can now ignore them all running with &lt;code&gt;--auto-gen-config&lt;/code&gt; option. This will create two files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;.rubocop_todo.yml&lt;/code&gt;: This file contains ignore rules for all current issues.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;.rubocop.yml&lt;/code&gt;: The main configuration file. Initially just inheriting/including the TODO file.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop --auto-gen-config
...
135 files inspected, 133 offenses detected
Created .rubocop_todo.yml.
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;The next run should return no issues, because they are all ignored in &lt;code&gt;.rubocop_todo.yml&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; rubocop
...
135 files inspected, no offenses detected
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Now you need to just commit all the changes and, optionally, add a step in your CI pipeline to run rubocop to check your source files.&lt;/p&gt;

&lt;h2&gt;
  
  
  2. Fix issues cop by cop
&lt;/h2&gt;

&lt;p&gt;The other strategy is to do this incrementally, using a script, to separate each cop fix in a different git commit. This helps in the future identifications of changes and why they happened.&lt;br&gt;
To do this, just run this script and it will apply and commit each issue in a separated commit.  &lt;/p&gt;

&lt;p&gt;It is important to create this script in a path ignored by git, like &lt;code&gt;tmp/script.rb&lt;/code&gt;. After create the script file, just call it running &lt;code&gt;ruby tmp/script.rb&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight ruby"&gt;&lt;code&gt;&lt;span class="c1"&gt;# tmp/script.rb&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"yaml"&lt;/span&gt;
&lt;span class="nb"&gt;require&lt;/span&gt; &lt;span class="s2"&gt;"rubocop"&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Generating config..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rubocop --auto-gen-config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rm .rubocop.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="c1"&gt;# OR git checkout .rubocop.yml if you want to start with some config&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Reading TODO config to get all possible issues..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;todo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;YAML&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;load_file&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;".rubocop_todo.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rm .rubocop_todo.yml"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;each_with_index&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_cop_settings&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;index&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Fixing &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; (&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;index&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;todo&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;count&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;eval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"RuboCop::Cop::&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;gsub&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="s2"&gt;"::"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;support_autocorrect?&lt;/span&gt;
    &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sb"&gt;`rubocop --auto-correct --force-default-config --only &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sb"&gt; --format files`&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;split&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"git add &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;join&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="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"git commit -m &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;chore: Correct source files with rubocop &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;cop&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; cop&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt; \
            --author &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;Rubocop Auto Correct &amp;lt;rubocop@rubocop&amp;gt;&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"  Does not support auto-correct"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Generating final TODO file with _uncorrectable_ issues..."&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="nb"&gt;system&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"rubocop --auto-gen-config"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;puts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;"Done"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

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



&lt;p&gt;It may take several minutes to run, depending on the number and size of your source files. &lt;/p&gt;

&lt;p&gt;Rubocop is designed to be safe, but some fixes could cause undesired behaviors, so it is important to have a great test coverage. You could run your unit tests in each iteration of this script or just run them in the end of the process. In this case, if an error occurs, you could use &lt;code&gt;git bisect&lt;/code&gt; to find which issue introduced the error.&lt;/p&gt;

&lt;p&gt;In the end the script generates commits like the ones bellow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight"&gt;&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$&amp;gt; git log --oneline
fad06ac (HEAD -&amp;gt; rubocop) chore: Correct source files with rubocop Style/WordArray cop
22aca61 chore: Correct source files with rubocop Style/ClassCheck cop
06b12a2 chore: Correct source files with rubocop Style/BracesAroundHashParameters cop
6dcace8 chore: Correct source files with rubocop Style/BlockDelimiters cop
a504890 chore: Correct source files with rubocop Style/BlockComments cop
1fae73b chore: Correct source files with rubocop Naming/RescuedExceptionsVariableName cop
10802ca chore: Correct source files with rubocop Lint/UnusedMethodArgument cop
bd11ffc chore: Correct source files with rubocop Lint/UnusedBlockArgument cop
b8e098d chore: Correct source files with rubocop Layout/TrailingBlankLines cop
4cabbd7 chore: Correct source files with rubocop Layout/Tab cop
f29e766 chore: Correct source files with rubocop Layout/SpaceInsidePercentLiteralDelimiters cop
b451890 chore: Correct source files with rubocop Layout/SpaceInsideHashLiteralBraces cop
ee9eae6 chore: Correct source files with rubocop Layout/SpaceInsideBlockBraces cop
f6611fd chore: Correct source files with rubocop Layout/SpaceInsideArrayLiteralBrackets cop
f858545 chore: Correct source files with rubocop Layout/SpaceInLambdaLiteral cop
3aeed2e chore: Correct source files with rubocop Layout/SpaceBeforeComment cop
8b40371 chore: Correct source files with rubocop Layout/SpaceBeforeBlockBraces cop
444f7ae chore: Correct source files with rubocop Layout/SpaceAroundEqualsInParameterDefault cop
42d4e69 chore: Correct source files with rubocop Layout/SpaceAfterComma cop
1acc003 chore: Correct source files with rubocop Layout/SpaceAfterColon cop
28ed714 chore: Correct source files with rubocop Layout/MultilineOperationIndentation cop
3e08ad7 chore: Correct source files with rubocop Layout/MultilineMethodCallIndentation cop
f4611e5 chore: Correct source files with rubocop Layout/MultilineMethodCallBraceLayout cop
6cc68b6 chore: Correct source files with rubocop Layout/MultilineHashBraceLayout cop
9f66fe9 chore: Correct source files with rubocop Layout/LeadingCommentSpace cop
...
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;



&lt;p&gt;Regardless of the strategy used, it is recommended to resolve all the issues that remained in the TODO file and, incrementally, move all ignores that really needs to be ignored to the main &lt;code&gt;.rubocop.yml&lt;/code&gt; file. This will ensure that you keeps improving your code or, or at least, maintaining its quality.&lt;/p&gt;

&lt;p&gt;Finally, rubocop is a great tool that helps us keeping and improving the quality of our code. It is extremelly recomended to use it in all of our ruby projects.&lt;/p&gt;

</description>
      <category>ruby</category>
      <category>code</category>
      <category>staticanalysis</category>
      <category>rubocop</category>
    </item>
    <item>
      <title>Hi, I'm Douglas Lise</title>
      <dc:creator>Douglas Lise</dc:creator>
      <pubDate>Mon, 03 Apr 2017 02:27:13 +0000</pubDate>
      <link>https://dev.to/douglaslise/hi-im-douglas-lise</link>
      <guid>https://dev.to/douglaslise/hi-im-douglas-lise</guid>
      <description>&lt;p&gt;I have been coding for 16 years.&lt;/p&gt;

&lt;p&gt;You can find me on Twitter as &lt;a href="https://twitter.com/douglaslise" rel="noopener noreferrer"&gt;@douglaslise&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;I live in Porto Alegre, Brazil.&lt;/p&gt;

&lt;p&gt;I work for Globo.com.&lt;/p&gt;

&lt;p&gt;I mostly program in these languages: Ruby,JavaScript.&lt;/p&gt;

&lt;p&gt;I am currently learning more about Reactive frameworks.&lt;/p&gt;

&lt;p&gt;Nice to meet you.&lt;/p&gt;

</description>
      <category>introduction</category>
    </item>
  </channel>
</rss>
