2012-05-03 14 views
41

Ho un lavoro Jenkins parametrizzato che richiede l'input di un ramo Git specifico in un repository Git specifico. Attualmente questo parametro è un parametro stringa.Riempi dinamicamente il parametro di scelta Jenkins con i rami Git in una repo specifica

Esiste un modo per rendere questo parametro un parametro di scelta e riempire dinamicamente l'elenco a discesa con i rami Git? Non voglio richiedere a qualcuno di mantenere questo parametro di scelta configurando manualmente il menu a discesa ogni volta che viene creato un nuovo ramo.

risposta

12

Extended Choice Parameter plugin consente di leggere le scelte da un file.

Ovviamente, ora avete un altro problema: come assicurarsi che il file sia aggiornato (che può essere fatto con un hook post-commit) e propagato a tutti gli utenti (che può essere fatto posizionando su un file server condiviso). Ma potrebbero esserci soluzioni migliori.

+4

Stiamo usando il [plug Extensible Scelta parametri] (https://wiki.jenkins-ci.org/display/JENKINS/Extensible+Choice+Parameter+plugin) con un script groovy: 'return [" "] .plus ([" powershell "," (git.exe ls-remote -h http: // review/Project) -replace '\\ w {40} \\ trefs/heads/'"] .execute(). text.tokenize())'. È PowerShell poiché si trova sulla macchina Windows, ma è possibile sostituirlo con un altro strumento per la sostituzione di RegEx. Ciò manterrà l'elenco aggiornato su ogni carico senza la necessità di file esterni. – Stoinov

+0

@Stoinov Mi piace molto la tua soluzione. Sto avendo problemi a far funzionare questo su un server Linux. – RockyMountainHigh

+0

Ho poca esperienza con linux, ma dovresti essere in grado di usare qualsiasi comando linux che possa sostituire l'elenco restituito da un comando git. – Stoinov

2

espandendo la risposta di @ malenkiy_scot. Ho creato un nuovo lavoro di jenkins per creare il file utilizzato da Extended Choice Plugin.

è possibile effettuare le seguenti operazioni (l'ho fatto come eseguire passaggi di shell a Jenkins, ma si poteva fare in uno script):

git ls-remote [email protected]:my/repo.git |grep refs/heads/* >tmp.txt 
sed -e 's/.*refs\/heads\///' tmp.txt > tmp2.txt 
tr '\n' ',' <tmp2.txt> tmp3.txt 
sed '1i\branches=' tmp3.txt > tmp4.txt 
tr -d '\n' <tmp4.txt> branches.txt 

ho poi usare il plugin Artefatto deployer a spingere quel file in una posizione condivisa, che è in un URL web, quindi basta usare "http: //localhost/branches.txt" nel plugin Extended Choice come url. funziona come un fascino.

+0

'grep refs/heads/*' non funziona per me – jspooner

+0

hmm. è un repo pubblico? puoi condividere l'url di git? Sarei curioso di vedere perché non ha funzionato – Ben

2

È possibile ottenere lo stesso utilizzando il estesa plug parametro scelta prima citato da malenkiy_scot e un semplice script PHP come segue (ammesso che abbiate qualche parte un server per distribuire script php che si può colpire dalla macchina Jenkins)

<?php 
chdir('/path/to/repo'); 
exec('git branch -r', $output); 
print('branches='.str_replace(' origin/','',implode(',', $output))); 
?> 

o

<?php 
exec('git ls-remote -h http://user:[email protected]', $output); 
print('branches='.preg_replace('/[a-z0-9]*\trefs\/heads\//','',implode(',', $output))); 
?> 

Con la prima opzione si avrebbe bisogno di clonare il repo. Con il secondo non lo fai, ma in entrambi i casi hai bisogno di git installato nel server che ospita il tuo script php. Con queste opzioni diventa completamente dinamico, non è necessario creare un file di elenco. Inserisci semplicemente l'URL nel tuo script nel campo "Proprietà file" del parametro di scelta estesa.

+0

Quindi hai bisogno di questo script php su un server web che ha git installato + credenziali ssh per accedere al server git. OK. Ma come si chiama questo script php dal Extended Parameter Plugin? –

2

Sì, ho scritto un piccolo script Groovy, che fa il trucco Si dovrebbe aggiungere una 'dinamica scelta del parametro' al vostro lavoro e personalizzare il seguente script Groovy alle vostre esigenze:

#!/usr/bin/groovy 

def gitURL = "git repo url" 
def command = "git ls-remote --heads --tags ${gitURL}" 

def proc = command.execute() 
proc.waitFor()    

if (proc.exitValue() != 0) { 
    println "Error, ${proc.err.text}" 
    System.exit(-1) 
} 

def text = proc.in.text 
# put your version string match 
def match = /<REGEX>/ 
def tags = [] 

text.eachMatch(match) { tags.push(it[1]) } 
tags.unique() 
tags.sort({ a, b -> 
     def a1 = a.tokenize('._-') 
     def b1 = b.tokenize('._-') 
     try { 
      for (i in 1..<[a1.size(), b1.size()].min()) { 
       if (a1[i].toInteger() != b1[i].toInteger()) return a1[i].toInteger() <=> b1[i].toInteger() 
      } 
      return 1 
     } catch (e) { 
      return -1; 
     } 
}) 
tags.reverse() 

ho il mio caso la stringa di versione era nel seguente formato XXXX e poteva avere rami utente nel formato XXX-username, ecc ... Quindi dovevo scrivere la mia funzione di ordinamento. Questo è stato il mio primo script groovy quindi se ci sono modi migliori di fare cosa mi piacerebbe sapere.

+0

Attenzione a questo script, eseguendolo in Dynamic Choice Parameter, si era schiantato il mio Jenkins (2.7, 2.8) –

+0

Puoi dire perché? hai un backtrace? Non l'ho mai provato su 2.X versione – sagi

+0

probabilmente è dovuto alla chiamata System.exit() (non correlata alla versione di Jenkins) –

13

Sono riuscito a ottenere questo risultato utilizzando Jenkins Dynamic Parameter Plug-in. Ho usato l'opzione dinamica scelta dei parametri e, per lo script scelte, ho usato il seguente:

proc1 = ['/bin/bash', '-c', "/usr/bin/git ls-remote -h ssh://[email protected]/path/to/repo.git"].execute() 
proc2 = ['/bin/bash', '-c', "awk '{print \$2}'"].execute() 
proc3 = ['/bin/bash', '-c', "sed s%^refs/heads%origin%"].execute() 

all = proc1 | proc2 | proc3 
String result = all.text 

String filename = "/tmp/branches.txt" 
boolean success = new File(filename).write(result) 

def multiline = "cat /tmp/branches.txt".execute().text 
def list = multiline.readLines() 
+2

Come aggiunta, ho trovato che ssh non è sempre disponibile ma non è necessariamente necessario. Un'alternativa sarebbe utilizzare qualcosa del tipo: 'proc1 = ['/ bin/bash', '-c',"/usr/bin/git ls-remote -h [email protected]: percorso/a/repo.git "]. execute()' Questa è una informazione particolarmente utile quando si lavora con github. – veritius

+0

Per qualche motivo, il ramo in ottava posizione viene sempre prelevato. (Ho circa 19 filiali). Non importa quale seleziono. Qualche idea se sia necessaria qualche altra configurazione nel lavoro di Jenkins? O c'è qualcosa di sbagliato nel plugin? Ho tenuto il campo 'ramo' vuoto. –

+1

Sembra che tu stia descrivendo un problema a valle, questo spiega solo come riempire dinamicamente un parametro con i tuoi rami git. Per utilizzare il ramo in una build di solito denominare il parametro "branch" e quindi in "Source Code Management" (con Git selezionato) utilizzare "$ {branch}" (senza virgolette) per "Branches to build" "Branch Specifier (vuoto per "qualsiasi") "campo. Spero possa aiutare. – veritius

53

Ho provato un paio di risposte menzionate in questo link, ma non riuscivo a capire come raccontare Jenkins sull'utente -selezione selezionata. Come menzionato nel mio precedente commento nel thread precedente, avevo lasciato vuoto il campo del selettore di ramo.

Ma, durante ulteriori indagini, ho trovato un altro modo per fare la stessa cosa - https://wiki.jenkins-ci.org/display/JENKINS/Git+Parameter+Plugin Ho trovato che questo metodo era molto più semplice e aveva meno cose da configurare!

Ecco cosa ho configurato -

  1. installato il plugin parametro git
  2. controllato il 'Questa build è parametrizzato' e ha aggiunto un 'parametro di Git'
  3. aggiunti i seguenti valori: Git Parameter plugin config in the job

  4. Quindi nella sezione git SCM del lavoro ho aggiunto lo stesso valore menzionato nella sezione 'Nome', come se fosse una variabile di ambiente. (Se leggete l'aiuto di questo parametro git plug attentamente, vi renderete conto questo) Branch Selector

Dopo questo ho appena eseguito la compilazione, ha scelto il mio ramo (Jenkins estrae questo ramo prima di costruire) ed è completato la compilazione con successo, E scegliendo il ramo che avevo specificato.

+4

Limitazioni/Bug noti: Il plug-in git non supporta l'installazione dello slave Jenkins con i repository git controllati solo sugli slave – AmokHuginnsson

+1

Mi sono emozionato, ma purtroppo è afflitto da un bug che non funziona t passare le credenziali al server git. Quindi, se hai bisogno di credenziali (come per i repository privati ​​di github), questo non funzionerà finché non verrà risolto JENKINS-28597. –

+1

Purtroppo non riesco a ottenere il nome del ramo senza 'origine /'. $ {BRANCH_SELECTOR ## * /} non funziona quando si iniettano variabili. – igor

0

Il seguente script Groovy sarebbe utile, se il lavoro non fa uso di "Source Code Management" direttamente (allo stesso modo "Git parametri plug-in"), ma hanno ancora accesso ad un (clonato) repository git locale:

import jenkins.model.Jenkins 

def envVars = Jenkins.instance.getNodeProperties()[0].getEnvVars() 
def GIT_PROJECT_PATH = envVars.get('GIT_PROJECT_PATH') 
def gettags = "git ls-remote -t --heads origin".execute(null, new File(GIT_PROJECT_PATH)) 

return gettags.text.readLines() 
     .collect { it.split()[1].replaceAll('\\^\\{\\}', '').replaceAll('refs/\\w+/', '') } 
     .unique() 

Vedi spiegazione completa qui: https://stackoverflow.com/a/37810768/658497

7

suo abbastanza semplice utilizzando il "Git Parameter Plug-in".

Aggiungi Nome come "SELECT_BRANCH" ## Assicurarsi che questa variabile venga utilizzata in seguito. Poi Parametro Tipo: Branch

Poi entrare in contatto con SCM: Seleziona: Git e ramo specificazione: $ {SELECT_BRANCH}

Per verificare, eseguire di seguito con guscio di Jenkins:

echo $ { SELECT_BRANCH}

env.enter descrizione dell'immagine qui

enter image description here

+1

Nel mio caso, lavoriamo con i rami di funzionalità. Jenkins dovrebbe creare automaticamente quando qualcuno inserisce il codice nel ramo della funzione. Quando il codice viene attivato dalle modifiche SCM, il parametro sarà vuoto. Quindi ho dovuto fare clic su Avanzate e digitare ** nella casella Valore predefinito per fare in modo che la build automatica come risultato di una modifica SCM funzioni. – Antony

0

È possibile eliminare la lettura/scrittura di file non necessari utilizzando text. La mia soluzione completa è la seguente:

proc1 = ['/bin/bash', '-c', 
    "/usr/bin/git ls-remote --heads ssh://repo_url.git"].execute() 
proc2 = ['/bin/bash', '-c', 
    "/usr/bin/awk ' { gsub(/refs\\/heads\\//, \"\"); print \$2 }' "].execute() 
all = proc1 | proc2 

choices = all.text 
return choices.split().toList();