Статьи

Как автоматически форматировать большую кодовую базу

Если вы вводите правила форматирования кода задним числом, вам придется решить проблему, как отформатировать существующую базу кода в соответствии с новыми правилами форматирования. Вы можете проверить каждый репозиторий кода один за другим в вашей IDE и нажать кнопку Автоформат всего проекта. Но это скучно и трата времени.

К счастью, Intellij IDEA имеет инструмент CLI формата в своей установке. Вы можете найти его по пути <ваша установка Intellij IDEA> / bin . Это называется format.sh .

В следующем разделе я хотел бы показать вам, как можно автоматизировать форматирование большой базы кода. Сначала я покажу подготовительные шаги, такие как экспорт настроек правила форматирования кода из IDE. Затем я продемонстрирую, как использовать CLI-Tool format.sh. В конце я покажу небольшой скрипт Groovy, который запрашивает все репозитории (в данном случае это репозитории Git), форматирует код и передает его обратно в удаленный SCM.

Препараты

Во-первых, нам нужна настройка правила форматирования кода, экспортированная из Intellij IDEA. В вашей Intellij IDEA следуйте следующему шагу

  1. Открыть файл -> Настройки — Редактор -> Стиль кода
  2. Нажмите на экспорт …
    форматирование кода
  3. Выберите имя для файла XML (например, Default.xml ) и место, где этот файл должен быть сохранен (например, / home / foo ).

Затем извлеките или клонируйте свой репозиторий SCM и запомните место, где вы извлекаете / клонируйте его (например, / home / foo / myrepository ).

Форматирование кода базы с помощью инструмента CLI format.sh

Для format.sh важны три параметра :

  • -s: установить путь к XML-файлу настроек стиля кода Intellij IDEA (в нашем примере: /home/foo/Default.xml ).
  • -r: установить, что каталоги должны проверяться рекурсивно.
  • путь <n>: укажите путь к файлу или каталогу, который должен быть отформатирован (в нашем примере: / home / foo / myrepository ).
01
02
03
04
05
06
07
08
09
10
> ./format.sh
IntelliJ IDEA 2018.2.4, build IC-182.4505.22 Formatter
Usage: format [-h] [-r|-R] [-s|-settings settingsPath] path1 path2...
-h|-help Show a help message and exit.
-s|-settings A path to Intellij IDEA code style settings .xml file.
-r|-R Scan directories recursively.
-m|-mask A comma-separated list of file masks.
path<n> A path to a file or a directory.
 
> /format.sh -r -s ~/Default.xml ~/myrepository

Возможно, что инструмент отменяет сканирование из-за java.lang.OutOfMemoryError: пространства кучи Java. Затем вам нужно увеличить максимальный объем памяти Java (-Xmx) в <ваша установка Intellij IDEA> / bin / idea64.vmoptions.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
> nano idea64.vmoptions
-Xms128m
-Xmx750m // <- here increase the maximum memory size
-XX:ReservedCodeCacheSize=240m
-XX:+UseConcMarkSweepGC
-XX:SoftRefLRUPolicyMSPerMB=50
-ea
-Dsun.io.useCanonCaches=false
-Djava.net.preferIPv4Stack=true
-Djdk.http.auth.tunneling.disabledSchemes=""
-XX:+HeapDumpOnOutOfMemoryError
-XX:-OmitStackTraceInFastThrow
-Dawt.useSystemAAFontSettings=lcd
-Dsun.java2d.renderer=sun.java2d.marlin.MarlinRenderingEngine

Groovy-скрипт для форматирования множества репозиториев подряд

Теперь мы хотим собрать все вместе. Скрипт должен делать четыре вещи:

  1. Найдите все URL репозитория, код которых должен быть отформатирован.
  2. Проверить / клонировать репозитории.
  3. Отформатируйте код во всех ветках каждого репозитория.
  4. Зафиксируйте и отправьте изменения в удаленный SCM.

Я выбираю Git в качестве SCM в моем примере. Поиск URL репозитория зависит от используемой вами системы управления Git (например, BitBucket, Gitlab, SCM Manager и т. Д.). Но подход во всей системе один и тот же:

  1. Вызовите RESTful API вашей системы управления Git.
  2. Разобрать объект JSON в ответе после URL.

Например, в BitBucket это так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
@Grab('org.codehaus.groovy.modules.http-builder:http-builder:0.7.1')
import groovyx.net.http.*
 
import static groovyx.net.http.ContentType.*
import static groovyx.net.http.Method.*
 
def cloneUrlsForProject() {
 
    def token = "BITBUCKET_TOKEN"
 
    def projects = []
    def cloneUrls = []
 
    def http = new HTTPBuilder(projectUrl)
    http.request(GET) {
        headers."Accept" = "application/json"
        headers."Authorization" = "Bearer ${token}"
 
        response.success = { resp -> projects = new JsonSlurper().parseText(resp.entity.content.text)}
 
        response.failure = { resp ->
            throw new RuntimeException("Error fetching clone urls for '${projectKey}': ${resp.statusLine}")
        }
    }
 
    projects.values.each { value ->
        def cloneLink = value.links.clone.find { it.name == "ssh" }
        cloneUrls.add(cloneLink.href)
    }
 
    return cloneUrls
}

Затем мы должны клонировать репозитории и оформить каждую ветку. В каждой ветке должен быть вызван формат .sh . Для операции git мы используем библиотеку jgit, а для вызова format.sh мы используем функцию Groovy для вызова процесса. В Groovy можно определить команду как строку, а затем вызвать метод execute () для этой строки, например «ls -l» .execute (). Таким образом, скрипт Groovy для трех последних задач будет выглядеть так:

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#!/usr/bin/env groovy
@Grab('org.eclipse.jgit:org.eclipse.jgit:5.1.2.201810061102-r')
import jgit.*
import org.eclipse.jgit.api.CreateBranchCommand
import org.eclipse.jgit.api.Git
import org.eclipse.jgit.api.ListBranchCommand
import org.eclipse.jgit.transport.UsernamePasswordCredentialsProvider
 
import java.nio.file.Files
 
 
def intellijHome = 'path to your idea home folder'
def codeFormatterSetting = 'path to your exported code formatter setting file'
def allRepositoriesUrls = ["http://scm/repo1","http://scm/repo2"] // for simplifying
 
allRepositoriesUrls.each { repository ->
    def repositoryName = repository.split('/').flatten().findAll { it != null }.last()
    File localPath = Files.createTempDirectory("${repositoryName}-").toFile()
    println "Clone ${repository} to ${localPath}"
    Git.cloneRepository()
       .setURI(repository)
       .setDirectory(localPath)
       .setNoCheckout(true)
       .setCredentialsProvider(new UsernamePasswordCredentialsProvider("user", "password")) // only needed when clone url is https / http
       .call()
       .withCloseable { git ->
        def remoteBranches = git.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call()
        def remoteBranchNames = remoteBranches.collect { it.name.replace('refs/remotes/origin/', '') }
 
        println "Found the following branches: ${remoteBranchNames}"
 
        remoteBranchNames.each { remoteBranch ->
            println "Checkout branch $remoteBranch"
            git.checkout()
               .setName(remoteBranch)
               .setCreateBranch(true)
               .setUpstreamMode(CreateBranchCommand.SetupUpstreamMode.TRACK)
               .setStartPoint("origin/" + remoteBranch)
               .call()
 
            def formatCommand = "$intellijHome/bin/format.sh -r -s $codeFormatterSetting $localPath"
 
            println formatCommand.execute().text
 
            git.add()
               .addFilepattern('.')
               .call()
            git.commit()
               .setAuthor("Automator", "[email protected]")
               .setMessage('Format code according to IntelliJ setting.')
               .call()
 
            println "Commit successful!"
        }
 
        git.push()
           .setCredentialsProvider(new UsernamePasswordCredentialsProvider("user", "password")) // only needed when clone url is https / http
           .setPushAll()
           .call()
 
        println "Push is done"
 
    }
}

У вас есть другой подход? Дайте мне знать и напишите комментарий ниже.

Опубликовано на Java Code Geeks с разрешения Сандры Парсик, партнера нашей программы JCG. Смотрите оригинальную статью здесь: Как автоматически форматировать большую кодовую базу

Мнения, высказанные участниками Java Code Geeks, являются их собственными.