用 Swift 实现 git hooks

169 阅读2分钟

添加 commit-msg 钩子

修改 提交的信息:获取分支名称中的 ticket number, 在提交信息中加入

1. 建立一个 Command Line 项目

在 xcode mack OS下新建一个 Command Line 项目

在 main.swift 中写入:

#!usr/bin/swift

import Foundation

2. 读取提交的信息

// 提交信息的文件路径
let commitMessageFile = CommandLine.arguments[1]   


guard let data = FileManager.default.contents(atPath: commitMessageFile),

      let commitMessage = String(data: data, encoding: .utf8) else {

    exit(1)

}

3. 执行命令, 返回命令输出结果

// swift 能执行命令的关键
func shell(_ command: String) -> String {

    let task = Process()

    let outputPipe = Pipe()

    let errorPipe = Pipe()

    

    task.standardOutput = outputPipe

    task.standardError = errorPipe

    task.arguments = ["-c", command]

    task.executableURL = URL(fileURLWithPath: "/bin/zsh")

    

    do {

        try task.run()

        task.waitUntilExit()

    } catch {

        print("There was an error running the command: \(command)")

        print(error.localizedDescription)

        exit(1)

    }

    

    guard let outputData = try? outputPipe.fileHandleForReading.readToEnd(),

          let outputString = String(data: outputData, encoding: .utf8) else {

        // Print error if needed

        if let errorData = try? errorPipe.fileHandleForReading.readToEnd(),

           let errorString = String(data: errorData, encoding: .utf8) {

            print("Encountered the following error running the command:")

            print(errorString)

        }

        exit(1)

    }

    return outputString

}

4. 获取分支名称

let gitBranchName = shell("git rev-parse --abbrev-ref HEAD")

    .trimmingCharacters(in: .newlines)

5. 获取分支中的 ticket Number

let stringRange = NSRange(location: 0, length: gitBranchName.utf16.count)

guard let regex = try? NSRegularExpression(pattern: #"(\w*-\d*)"#, options: .anchorsMatchLines),

    let match = regex.firstMatch(in: gitBranchName, range: stringRange) else {

    exit(0) // 如果 match 不到, 正常退出, 继续提交(不放弃提交)

}

let range = match.range(at: 1)

let ticketNumber = (gitBranchName as NSString)

    .substring(with: range)

    .trimmingCharacters(in: .newlines)

⚠️ 请注意,如果没有匹配项(即分支名称中不包含JIRA问题编号),脚本将以0的状态退出,允许提交继续进行,而不进行任何更改。 exit(1) 表示放弃本次提交

6. 修改提交信息

if !commitMessage.contains(ticketNumber) {

    do {

        try "\(ticketNumber) - \(commitMessage.trimmingCharacters(in: .newlines))"

            .write(toFile: commitMessageFile, atomically: true, encoding: .utf8)

    } catch {

        print("Could not write to file \(commitMessageFile)")

        exit(1)

    }

}

7. 配置 git 钩子

// 这一步很关键, 别弄错了
chmod +x main.swift
mv main.swift <path_to_your_repo>/.git/hooks/commit-msg

8. 测试结果

GitHookDemo % git checkout -b story/ISSUE-1234_some-awesome-feature-work

    Switched to a new branch 'story/ISSUE-1234_some-awesome-feature-work'

GitHookDemo % touch hello.txt

GitHookDemo % git add .

GitHookDemo % git commit -m 'add hello txt'

[story/ISSUE-1234_some-awesome-feature-work aa3eaff] ISSUE-1234 - add hello txt

 1 file changed, 0 insertions(+), 0 deletions(-)

参考链接

git 钩子指导文档 有各种钩子的说明

常用钩子