如何自动格式化大型代码库

如果追溯性地引入代码格式化规则,则必须解决如何根据新的格式化规则格式化现有代码库的问题。 您可以在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 )。

通过

三个参数对于format.sh很重要

  • -s:设置Intellij IDEA代码样式设置.xml文件的路径(在我们的示例中为/home/foo/Default.xml )。
  • -r:设置应递归扫描目录。
  • path <n>:设置应格式化的文件或目录的路径(在我们的示例中为/ home / foo / myrepository )。
> ./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堆空间而取消了扫描 然后,您必须在<您的Intellij IDEA安装> /bin/idea64.vmoptions中增加Java的最大内存大小(-Xmx)

> 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管理器等)。 但是方法在所有系统中都是相同的:

  1. 调用Git管理系统的RESTful API。
  2. 在网址之后解析响应中的JSON对象。

例如,在BitBucket中是这样的:

@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 projectUrl = "https://scm/rest/api/1.0/projects/PROJECT_KEY/repos?limit=1000"
    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
}

然后,我们必须克隆存储库并检出每个分支。 在每个分支中,必须调用format.sh 。 对于git操作,我们使用jgit库,对于format.sh调用,我们使用Groovy功能进行流程调用。 在Groovy中,可以将命令定义为String,然后在此String上调用方法execute() ,例如“ ls -l” .execute()。 因此,最后三个任务的Groovy脚本如下所示:

#!/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", "no-reply@yourcompany.com")
               .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"

    }
}

您还有其他方法吗? 让我知道并在下面写评论。

翻译自: https://www.javacodegeeks.com/2018/10/format-large-code-base-automatically.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值