Groovy Nested Closures - как передать хеш? - PullRequest
0 голосов
/ 03 февраля 2019

Я хотел бы загрузить замыкание для моей сборки Jenkins, но передать ему некоторые переменные, которые являются общими для любого типа сборки (Go, Java, Docker), которая происходит в нашей системе.Поскольку я загружаю конкретное замыкание из отдельного файла Groovy, он не видит эти переменные.В целях упрощения примера я закомментировал нагрузку и включил это закрытие.

Я немного не уверен, как это сделать - как передать конфигурацию из buildProject в buildSpecificProject?Я имею в виду это неправильно?

#!/usr/bin/groovy

//def buildSpecificProject = load 'buildSpecificProject.groovy'

def buildSpecificProject = {  body->  

   def config = [:]
   body.resolveStrategy = Closure.DELEGATE_FIRST
   body.delegate = config
   body()

   println config.name
   println config.builddirectory
}

def buildProject = { projbody -> 
   def config = [:]
   projbody.resolveStrategy = Closure.DELEGATE_FIRST
   projbody.delegate = config
   projbody()

   config.builddirectory = "/bar"

   return config
}

try {
    def newProjectVersion =  buildSpecificProject { body ->
      buildProject { projbody ->
         name = 'projectname'
         versionPrefix = "4.2.0"
         fetchFromURL = 'git@github.com:myorg/myproject.git'
      }
    }
    println "New Project Version = ${newProjectVersion}\n"
} catch (err) {
    println err
}

1 Ответ

0 голосов
/ 05 февраля 2019

У меня нет опыта работы со сценариями сборки в Jenkins, поэтому, возможно, мой ответ неприменим, но с точки зрения только Groovy ситуация выглядит следующим образом:

Переменная config в buildSpecificProject является локальной переменной,к которому вы не имеете доступа, если только вы не подвергаете его или его значение.Прямо сейчас вы делаете это через настройку делегата на самом деле.

Если мы говорим, что buildProject вызывается только из блока, заданного для buildSpecificProject, то блок, данный для buildProject, является вложением Closure, вложенным в Closure, данное для buildSpecificProject.Этот объект Closure будет иметь владельца свойства, который в этом случае будет ссылаться на включающий экземпляр Closure (см. http://groovy -lang.org / closures.html # _owner_of_a_closure ).Из этого мы знаем, что он установил конфигурацию как делегат, таким образом, вы можете сделать projbody.owner.delegate для доступа к набору конфигурации с помощью buildSpecificProject.

Но на самом деле я хотел бы сделать что-то вроде этого:

def buildSpecificProject = {  body ->  
  def config = [:]
  body.resolveStrategy = Closure.DELEGATE_FIRST
  body.delegate = [config: config]  // expose config
  body()

  println config.name
  println config.builddirectory
  return config
}

def buildProject = { config, projbody -> 
   projbody()
   config.builddirectory = "/bar"
}

try {
    def newProjectVersion =  buildSpecificProject { body ->
      // make config accessible to buildProject by providing it as parameter
      buildProject(config) { projbody ->  
         config.name = 'projectname'
         config.versionPrefix = "4.2.0"
         config.fetchFromURL = 'git@github.com:myorg/myproject.git'
      }
    }
    println "New Project Version = ${newProjectVersion}\n"
} catch (err) {
    println err
}

Как видите, для buildSpecificProject действительно достаточно установить делегата, который я установил для карты с одним ключом с именем config, содержащим фактическую конфигурацию.Недостаток, конечно, в том, что вам теперь нужно сделать config.name.Также обратите внимание на вызов "buildProject (config) {projbody ->", который дает конфигурацию для buildProject.И, конечно, мы можем объединить обе идеи:

def buildSpecificProject = {  body ->  
  def config = [:]
  body.resolveStrategy = Closure.DELEGATE_FIRST
  body.delegate = config
  body()

  println config.name
  println config.builddirectory
  return config
}

def buildProject = { config, projbody ->
   projbody()
   config.builddirectory = "/bar"
}

try {
    def newProjectVersion =  buildSpecificProject {
      buildProject(delegate) { projbody ->
         name = 'projectname'
         versionPrefix = "4.2.0"
         fetchFromURL = 'git@github.com:myorg/myproject.git'
      }
    }
    println "New Project Version = ${newProjectVersion}\n"
} catch (err) {
    println err
}

Но я бы порекомендовал это не так сильно, так как я не хотел бы зависеть от делегата таким образом.Я могу сломаться слишком легко.

...