Bitbucket - Groovy 预接收挂钩

Bitbucket - Groovy Pre-receive Hook

我正在尝试理解以下代码片段 following site

<% refChanges.getCommits(repository).each { commit -> %>
    - ${commit.author.name} | ${commit.displayId} | ${commit.message} | ${commit.authorTimestamp}
<% } %>

该脚本正在使用 getCommits 方法,但是当我查看 the documentation for the RefChange interface 时,我没有看到任何此类方法。

我认为自己是专家 Java 开发人员,但我在 Groovy 方面没有实用的知识,所以我假设我误解了 Groovy 或 BitBucket 文档(或两者) .

在 Groovy 中,可以通过 meta-programming 将方法添加到 class 或 run-time 的接口。由于RefChange接口没有包含getCommits(),那肯定是在添加方法after-the-fact。根据他们的示例代码,看起来他们正在使用 meta-class.

getCommits() 在哪里?

例如,在 Groovy 中,Collection 接口获取方法 findAll()(以及许多其他方法)。我可以确认如下:

assert Collection.metaClass.metaMethods*.name.contains('findAll') == true

上面的代码获取所有 元方法 的名称,然后使用 contains() 查看是否找到匹配项。您可以用类似的方式为 getCommits() 确认相同的内容:

assert Collection.metaClass.metaMethods*.name.contains('getCommits') == true

请注意,我指定了 Collection 而不是 RefChange,因为 refChangesRefChangeCollection。所以我认为 Atlasssian 将 getCommits() 插入 Collection 作为一种方便的方法。

它是如何工作的?

为了了解发生了什么,我将删除模板代码:

refChanges.getCommits(repository).each { commit ->
    "${commit.author.name} | ${commit.displayId} | ${commit.message} | ${commit.authorTimestamp}"
}
  1. getCommits() returns com.atlassian.bitbucket.commit.CommitCollection
  2. Object.each(Closure) 由 Groovy GDK 添加(是的,添加到对象 class 中)并重复调用 Closure;每次用Collection.
  3. 的一个元素
  4. 虽然在示例代码中并不明显,但 each(Closure) 中的行是 GString。基本上 ${...} 中的表达式被评估,整个事情被连接成 String.