2012-01-23 14 views
14

Imagine un trabajo A de Jenkins que tarda 1 minuto en ejecutarse, y el trabajo B, que tarda 5 minutos.Trabajo parametrizado de Jenkins que solo pone en cola una compilación

Si configuramos el trabajo A para desencadenar el trabajo B, mientras el trabajo B está ejecutándose el trabajo A puede ejecutarse 5 veces antes de que B finalice. Sin embargo, Jenkins no agrega 5 compilaciones a la cola del trabajo B, lo cual es excelente porque de lo contrario el trabajo A acelerado crearía un retraso acumulado de compilaciones para trabajo lento y lento B.

Sin embargo, ahora queremos tener trabajo Un disparador B como un trabajo parametrizado, usando parameterized trigger plugin. Los trabajos parametrizados do hacen cola en un backlog, lo que significa que el trabajo A está creando felizmente una gran pila de construcciones para el trabajo B, que posiblemente no puede mantener el ritmo.

Tiene sentido agregar una nueva compilación parametrizada a la cola cada vez que se activa, ya que los parámetros pueden ser diferentes. Jenkins no siempre debe asumir que una nueva compilación parametrizada hace innecesarios a los que estaban previamente en cola.

Sin embargo, en nuestro caso, realmente nos gustaría. Job A crea y empaqueta nuestra aplicación, luego Job B la implementa en un entorno de producción y ejecuta un conjunto más pesado de pruebas de integración. También tenemos una compilación C que se implementa en otro entorno e incluso hace más pruebas, por lo que este es un patrón creciente para nosotros.

Queremos que la cola de nuestro trabajo parametrizado B solo conserve la última compilación añadida; cada nueva construcción reemplazaría cualquier trabajo actualmente en la cola.

¿Hay alguna buena manera de lograr esto?

Respuesta

3

Puede deshacerse del Complemento disparador parametrizado y, en su lugar, usar el disparo tradicional. Como dijiste, esto evitaría que la cola de trabajo B se acumulara.

¿Cómo pasar los parámetros de A a B? Haga que el trabajo A arroje los parámetros en la salida de la consola. En el trabajo B, para obtener estos parámetros de compilación, examine la salida de la última compilación A de la consola (¿con una secuencia de comandos de Python, quizás?).

+0

Puede guardar los parámetros en un archivo de propiedades y usar el complemento envInject para leer las propiedades. –

+1

Los parámetros se pueden pasar en un activador tradicional también. –

1

En caso de que esté usando Git, ahora esto es compatible con los "hashes git Combine Queued" en la opción Triggering/Parameters/Pass-through. La primera versión del plugin Git que realmente debe trabajar con esto es 1.1.27 (ver Jenkins-15160)

5

Añadir un B "Sistema de escritura maravilloso" etapa de pre-construcción de trabajo que comprueba (más reciente) en cola trabajos del mismo nombre y rescata si se encuentra:

def name = build.properties.environment.JOB_NAME 
def queue = jenkins.model.Jenkins.getInstance().getQueue().getItems() 
if (queue.any{ it.task.getName() == name }) { 
    println "Newer " + name + " job(s) in queue, aborting" 
    build.doStop() 
} else { 
    println "No newer " + name + " job(s) in queue, proceeding" 
} 
+0

¡Gracias! Esta fue la mejor solución que he encontrado hasta ahora. Funcionó como un encanto y también puedo hacer un seguimiento de las compilaciones 'detenido'. – Marcelo

+0

Un problema con este método es que la próxima compilación no puede mostrar los cambios de VCS: 'WARN: los datos de revisión para la compilación anterior no están disponibles; no se puede determinar el registro de cambios' – mrtnlrsn

+0

@Marcelo ¿Dónde se ejecuta esto en un trabajo de estilo libre (no tiene pre buildstep) – lvthillo

0

La solución de Ron funcionó para mí.Si no te gusta tener montón de cancelado se basa en la historia de la acumulación puede agregar el siguiente sistema de escritura maravilloso de trabajo A antes de desencadenar el trabajo B:

import hudson.model.* 
def q = jenkins.model.Jenkins.getInstance().getQueue() 
def items = q.getItems() 
for (i=0;i<items.length;i++){ 
    if(items[i].task.getName() == "JobB"){ 
    items[i].doCancelQueue() 
    } 
} 
0

Aquí es una opción más flexible si sólo se preocupa por una pocos parámetros coincidentes. Esto es especialmente útil cuando un trabajo se desencadena externamente (es decir, desde GitHub o Stash) y algunos parámetros no necesitan una compilación separada.

Si los parámetros marcados coinciden tanto en valor como en existencia tanto en la compilación actual como en la compilación en cola, se anulará la compilación actual y la descripción mostrará que una compilación futura contiene los mismos parámetros verificados (junto con lo que fueron)

Se podría modificar para cancelar todos los demás trabajos en cola excepto el último si no desea que el historial de compilación muestre los trabajos cancelados.

checkedParams = [ 
    "PARAM1", 
    "PARAM2", 
    "PARAM3", 
    "PARAM4", 
] 

def buildParams = null 
def name = build.project.name 
def queuedItems = jenkins.model.Jenkins.getInstance().getQueue().getItems() 

yieldToQueuedItem = false 
for(hudson.model.Queue.Item item : queuedItems.findAll { it.task.getName() == name }) { 
    if(buildParams == null) {  
     buildParams = [:] 
     paramAction = build.getAction(hudson.model.ParametersAction.class) 
     if(paramAction) { 
      buildParams = paramAction.getParameters().collectEntries { 
       [(it.getName()) : it.getValue()] 
      } 
     } 
    } 
    itemParams = [:] 
    paramAction = item.getAction(hudson.model.ParametersAction.class) 
    if(paramAction) { 
     itemParams = paramAction.getParameters().collectEntries { 
      [(it.getName()) : it.getValue()] 
     } 
    } 

    equalParams = true 
    for(String compareParam : checkedParams) { 
     itemHasKey = itemParams.containsKey(compareParam) 
     buildHasKey = buildParams.containsKey(compareParam) 
     if(itemHasKey != buildHasKey || (itemHasKey && itemParams[compareParam] != buildParams[compareParam])) { 
      equalParams = false 
      break; 
     } 
    } 
    if(equalParams) { 
     yieldToQueuedItem = true 
     break 
    } 
} 

if (yieldToQueuedItem) { 
    out.println "Newer " + name + " job(s) in queue with matching checked parameters, aborting" 
    build.description = "Yielded to future build with:" 
    checkedParams.each { 
     build.description += "<br>" + it + " = " + build.buildVariables[it] 
    } 

    build.doStop() 
    return 
} else { 
    out.println "No newer " + name + " job(s) in queue with matching checked parameters, proceeding" 
} 
0

Lo siguiente se basa en la solución de Ron, pero con algunas correcciones a trabajar en mi Jenkins 2 incluyendo la eliminación de java.io.NotSerializableException excepción y gastos que el formato de getName() es algunas veces diferente de la de JOB_NAME

// Exception to distinguish abort due to newer jobs in queue 
class NewerJobsException extends hudson.AbortException { 
    public NewerJobsException(String message) { super(message); } 
} 

// Find jenkins job name from url name (which is the most consistently named 
// field in the task object) 
// Known forms: 
// job/NAME/ 
// job/NAME/98/ 
@NonCPS 
def name_from_url(url) 
{ 
    url = url.substring(url.indexOf("/") + 1); 
    url = url.substring(0, url.indexOf("/")); 
    return url 
} 

// Depending on installed plugins multiple jobs may be queued. If that is the 
// case skip this one. 
// http://stackoverflow.com/questions/26845003/how-to-execute-only-the-most-recent-queued-job-in-jenkins 
// http://stackoverflow.com/questions/8974170/jenkins-parameterized-job-that-only-queues-one-build 
@NonCPS 
def check_queue() 
{ 
    def name = env.JOB_NAME 
    def queue = jenkins.model.Jenkins.getInstance().getQueue().getItems() 
    if (queue.any{ name_from_url(it.task.getUrl()) == name }) { 
     print "Newer ${name} job(s) in queue, aborting" 
     throw new NewerJobsException("Newer ${name} job(s) in queue, aborting") 
    } else { 
     print "No newer ${name} job(s) in queue, proceeding" 
    } 
} 
Cuestiones relacionadas