Jenkins: nie można zdefiniować zmiennej na etapie potoku

106

Próbuję utworzyć deklaratywny skrypt potoku Jenkins, ale mam problemy z prostą deklaracją zmiennej.

Oto mój skrypt:

pipeline {
   agent none
   stages {
       stage("first") {
           def foo = "foo" // fails with "WorkflowScript: 5: Expected a step @ line 5, column 13."
           sh "echo ${foo}"
       }
   }
}

Jednak pojawia się ten błąd:

org.codehaus.groovy.control.MultipleCompilationErrorsException: startup failed:
WorkflowScript: 5: Expected a step @ line 5, column 13.
           def foo = "foo"
           ^

Jestem na Jenkins 2.7.4 i Pipeline 2.4.

Malcolm Crum
źródło

Odpowiedzi:

101

Model deklaratywny dla Jenkins Pipelines ma ograniczony podzbiór składni, na który pozwala w stageblokach - zobacz przewodnik po składni, aby uzyskać więcej informacji . Możesz ominąć to ograniczenie, zawijając kroki w script { ... }blok, ale w rezultacie utracisz walidację składni, parametrów itp. W scriptbloku.

abayer
źródło
5
A jeśli chcę użyć tej zmiennej poza blokiem skryptu?
Jan Steinke,
3
aby używać zmiennej poza blokiem skryptu, sprawdź ten stackoverflow.com/questions/43879733/ ...
Senthil A Kumar
56

Myślę, że błąd nie pochodzi z określonej linii, ale z pierwszych 3 linii. Spróbuj tego zamiast tego:

node {
   stage("first") {
     def foo = "foo"
     sh "echo ${foo}"
   }
}

Myślę, że miałeś kilka dodatkowych wierszy, które są nieprawidłowe ...

EDYTOWAĆ

Z deklarowanej dokumentacji modelu potoku wynika , że environmentdo zadeklarowania zmiennych należy użyć bloku deklaracji, np .:

pipeline {
   environment {
     FOO = "foo"
   }

   agent none
   stages {
       stage("first") {
           sh "echo ${FOO}"
       }
   }
}
Pom12
źródło
1
Możesz również dodać blok środowiska do etapu (np. Jeśli zmienna zależy od czegoś, co zostało zrobione na wcześniejszym etapie).
Tereza Tomcova
34

Zgadzam się z @ Pom12, @abayer. Aby uzupełnić odpowiedź, musisz dodać blok skryptu

Spróbuj czegoś takiego:

pipeline {
    agent any
    environment {
        ENV_NAME = "${env.BRANCH_NAME}"
    }

    // ----------------

    stages {
        stage('Build Container') {
            steps {
                echo 'Building Container..'

                script {
                    if (ENVIRONMENT_NAME == 'development') {
                        ENV_NAME = 'Development'
                    } else if (ENVIRONMENT_NAME == 'release') {
                        ENV_NAME = 'Production'
                    }
                }
                echo 'Building Branch: ' + env.BRANCH_NAME
                echo 'Build Number: ' + env.BUILD_NUMBER
                echo 'Building Environment: ' + ENV_NAME

                echo "Running your service with environemnt ${ENV_NAME} now"
            }
        }
    }
}
Si Zi
źródło
4
Zwróć uwagę, że w tym przykładzie założono, że istnieje już zdefiniowana zmienna środowiskowa „ENVIRONMENT_NAME” dostępna dla jenkins.
Alberto
1
Czy blok skryptu może zmienić wartości środowiska?
pitchblack408
Tak, możesz zmienić wartość środowiska wewnątrz bloku de script.
NicoPaez
8

W Jenkins 2.138.3 istnieją dwa różne typy rurociągów.

Potoki deklaratywne i oparte na skryptach.

„Deklaratywne potoki to nowe rozszerzenie potoku DSL (w zasadzie jest to skrypt potoku z tylko jednym krokiem, krokiem potoku z argumentami (zwanymi dyrektywami). Te dyrektywy powinny mieć określoną składnię. Celem tego nowego formatu jest to, że jest bardziej rygorystyczny i dlatego powinien być łatwiejszy dla nowych użytkowników potoków, umożliwiać edycję graficzną i nie tylko. Potoki skryptowe to rozwiązanie zastępcze dla zaawansowanych wymagań ”.

Jenkins Pipeline: Agent kontra Węzeł?

Oto przykład użycia zmiennych środowiskowych i globalnych w potoku deklaratywnym. Z tego, co mogę powiedzieć, środowisko jest statyczne po ustawieniu.

def  browser = 'Unknown'

pipeline {
    agent any
    environment {
    //Use Pipeline Utility Steps plugin to read information from pom.xml into env variables
    IMAGE = readMavenPom().getArtifactId()
    VERSION = readMavenPom().getVersion()


    }
    stages {
        stage('Example') {
            steps {
                script {
                    browser = sh(returnStdout: true, script: 'echo Chrome')
                }
            }
        }
        stage('SNAPSHOT') {
                when {
                    expression { 
                        return !env.JOB_NAME.equals("PROD") && !env.VERSION.contains("RELEASE")
                    }
                }
                steps {
                    echo "SNAPSHOT"
                    echo "${browser}"
                }
            }
            stage('RELEASE') {
                when {
                    expression { 
                        return !env.JOB_NAME.equals("TEST") && !env.VERSION.contains("RELEASE")
                    }
                }
                steps {
                    echo "RELEASE"
                    echo "${browser}"
                }
            }
    }//end of stages 
}//end of pipeline
czarna smoła408
źródło
W powyższym kodzie pojawia się następujący błąd: [Pipeline] Początek potoku [Pipeline] readMavenPom [Pipeline] Koniec rurociągu org.jenkinsci.plugins.workflow.steps.MissingContextVariableException: Brak wymaganej klasy kontekstu hudson.FilePath Być może zapomniałeś otoczyć kod z krokiem, który to zapewnia, na przykład: node
mancocapac
Nie, to działało tak, jak jest. Jest to potok deklaratywny. Agent w dowolny sposób oznacza, że ​​może działać na dowolnym węźle
pitchblack408
@ pitchblack408, masz rację, miałem [agenta brak] na szczycie mojego rurociągu. Nie wiesz, co masz na myśli, mówiąc: środowisko jest statyczne po ustawieniu? Można je zmienić w skrypcie, np. Script {IMAGE = "newVal}
mancocapac
Przykład, spójrz na OBRAZ. Nie jest zmienną, która może lub powinna zostać zmieniona przez rurociąg. Rozumiem, że po zdefiniowaniu należy go traktować jako wartość statyczną jako część środowiska.
pitchblack408
0

Używasz Declarative Pipeline, który wymaga kroku skryptu, aby wykonać kod Groovy. Jest to ogromna różnica w porównaniu ze skryptem potokowym, w którym nie jest to konieczne.

Oficjalna dokumentacja mówi, co następuje:

Krok skryptu pobiera blok Scripted Pipeline i wykonuje go w Declarative Pipeline.

pipeline {
   agent none
   stages {
       stage("first") {
           script {
               def foo = "foo" 
               sh "echo ${foo}"
           }
       }
   }
}
Michael Kemmerzell
źródło