ไม่สามารถเรียกใช้คำสั่งเชลล์ใน Groovy ใน Jenkins

ฉันกำลังพยายามรับค่าบางอย่างจากทาสโดยการรันคำสั่งเชลล์เช่น:

git rev-parse HEAD
git config --get remote.origin.url

วิธีที่ฉันได้ลองเขียนสำหรับสิ่งนี้คือ:

def executeCommand(String command) {
    stdout = sh script: command, returnStdout: true
    return stdout.trim()
}

ตอนนี้เมื่อฉันพยายามรันคำสั่งแรก:

output = executeCommand('git rev-parse HEAD')

ฉันได้รับข้อผิดพลาด:

[Running] groovy "/Users/user-a/Documents/cmd.groovy"
Caught: groovy.lang.MissingMethodException: No signature of method: cmd.sh() is applicable for argument types: (LinkedHashMap) values: [[script:git rev-parse HEAD, returnStdout:true]]
Possible solutions: is(java.lang.Object), use([Ljava.lang.Object;), run(), run(), any(), tap(groovy.lang.Closure)
groovy.lang.MissingMethodException: No signature of method: cmd.sh() is applicable for argument types: (LinkedHashMap) values: [[script:git rev-parse HEAD, returnStdout:true]]
Possible solutions: is(java.lang.Object), use([Ljava.lang.Object;), run(), run(), any(), tap(groovy.lang.Closure)
    at cmd.executeCommand(cmd.groovy:2)
    at cmd.run(cmd.groovy:6)

ฉันยังลอง:

output = command.execute().text

แต่สิ่งนี้กลับไม่ได้อะไรเลย

ฉันไม่มีแนวคิดเกี่ยวกับวิธีการรันคำสั่งเชลล์ใน Groovy ใน Jenkins และบันทึกผลลัพธ์

รายละเอียดเพิ่มเติม

ฉันกำลังทำงานร่วมกับไลบรารีที่แชร์ของ Jenkins ฉันได้เปิดเผยวิธีการสำหรับ Jenkinsfile ของฉันด้วยชื่อ getLatestBuildDetails() วิธีการนี้ถูกกำหนดไว้ภายในห้องสมุดของฉัน การดำเนินการอย่างหนึ่งภายในวิธีการนี้คือการดำเนินการคำสั่ง git ในเครื่อง ดังนั้นเพื่อที่จะรันคำสั่งเชลล์ใด ๆ ในเครื่อง ฉันได้สร้างฟังก์ชัน executeCommand ซึ่งใช้คำสั่งจริงเพื่อรันเป็น String และดำเนินการและส่งคืนเอาต์พุตเพื่อใช้ในภายหลังภายใน getLatestBuildDetails()


person Community    schedule 17.08.2018    source แหล่งที่มา
comment
คุณลองฮาร์ดโค้ดโดยตรงแล้วลอง "git rev-parse HEAD"..execute().text   -  person rohit thomas    schedule 17.08.2018
comment
แน่ใจว่า .execute() เหมาะกับ jenkins-pipeline หรือไม่   -  person StephenKing    schedule 17.08.2018
comment
อ่า.. @Jason Stanley คุณแน่ใจหรือว่าคุณกำลังทำอะไรอยู่? sh เป็นขั้นตอนหนึ่งของ ไปป์ไลน์ของ Jenkins แต่ส่วนที่เหลือของสิ่งที่คุณโพสต์กลับไม่เป็นเช่นนั้น ฟังดูไม่มากเท่ากับที่คุณใช้ไปป์ไลน์ของเจนกินส์จริงๆ คุณช่วยเพิ่มรายละเอียดเพิ่มเติมได้ไหมว่าคุณใช้รหัสที่ให้มาที่ไหน?   -  person StephenKing    schedule 17.08.2018
comment
@StephenKing ฉันเพิ่มมุมมองอีกเล็กน้อย ฟังก์ชัน executeCommand ใช้งานได้เฉพาะเมื่อฉันเรียก @NonCPS ไม่เช่นนั้นจะใช้ไม่ได้   -  person    schedule 17.08.2018


คำตอบ (2)


คลาสไลบรารีไม่สามารถเรียกขั้นตอนต่างๆ เช่น sh หรือ git ได้โดยตรง อย่างไรก็ตาม พวกเขาสามารถนำเมธอดไปใช้นอกขอบเขตของคลาสที่ปิดล้อม ซึ่งจะเรียกใช้ขั้นตอนไปป์ไลน์ ตัวอย่างเช่น:

// src/org/foo/Zot.groovy
package org.foo;

def checkOutFrom(repo) {
  git url: "[email protected]:jenkinsci/${repo}"
}

return this

ซึ่งสามารถเรียกได้จาก Scripted Pipeline:

def z = new org.foo.Zot()
z.checkOutFrom(repo)

วิธีการนี้มีข้อจำกัด ตัวอย่างเช่น ป้องกันการประกาศซูเปอร์คลาส

อีกทางหนึ่ง ชุดของขั้นตอนสามารถส่งผ่านอย่างชัดเจนโดยใช้สิ่งนี้ไปยังคลาสไลบรารี ใน Constructor หรือเพียงวิธีเดียว:

package org.foo
class Utilities implements Serializable {
  def steps
  Utilities(steps) {this.steps = steps}
  def mvn(args) {
    steps.sh "${steps.tool 'Maven'}/bin/mvn -o ${args}"
  }
}

เมื่อบันทึกสถานะในคลาส เช่นข้างต้น คลาสจะต้องใช้อินเทอร์เฟซแบบอนุกรมได้ เพื่อให้แน่ใจว่าไปป์ไลน์ที่ใช้คลาสดังที่เห็นในตัวอย่างด้านล่าง สามารถระงับและดำเนินการต่อในเจนกินส์ได้อย่างเหมาะสม

@Library('utils') import org.foo.Utilities
def utils = new Utilities(this)
node {
  utils.mvn 'clean package'
}

หากไลบรารีจำเป็นต้องเข้าถึงตัวแปรโกลบอล เช่น env ตัวแปรเหล่านั้นควรถูกส่งผ่านไปยังคลาสไลบรารีหรือเมธอดอย่างชัดเจนในลักษณะที่คล้ายกัน

แทนที่จะส่งตัวแปรจำนวนมากจาก Scripted Pipeline ไปยังไลบรารี

package org.foo
class Utilities {
  static def mvn(script, args) {
    script.sh "${script.tool 'Maven'}/bin/mvn -s ${script.env.HOME}/jenkins.xml -o ${args}"
  }
}

ตัวอย่างข้างต้นแสดงสคริปต์ที่ถูกส่งผ่านไปยังวิธีคงที่วิธีหนึ่ง ซึ่งเรียกใช้จากไปป์ไลน์แบบสคริปต์ดังนี้:

@Library('utils') import static org.foo.Utilities.*
node {
  mvn this, 'clean package'
}

ในกรณีของคุณคุณควรเขียนดังนี้:

def getLatestBuildDetails(context){
    //...
    executeCommand(context, 'git rev-parse HEAD')
    //...
}

def executeCommand(context, String command) {
    stdout = script.sh(script: command, returnStdout: true)
    return stdout.trim()
}

ไฟล์เจนกินส์:

@Library('library_name') _
getLatestBuildDetails(this)

สำหรับข้อมูลเพิ่มเติม โปรดดูเอกสารไลบรารีที่ใช้ร่วมกันของ jenkins: https://jenkins.io/doc/book/pipeline/shared-libraries/

person grolegor    schedule 26.08.2018

ลองใช้sh step แทนการดำเนินการ :)

แก้ไข: ฉันจะใช้ execute() หรือซึ่งฉันคิดว่าดีกว่านี้อีก grgit. ฉันคิดว่าคุณจะไม่ได้รับเอาต์พุตใดๆ เมื่อคุณรัน cmd.execute().text เนื่องจาก .text ส่งคืนเอาต์พุตมาตรฐานของคำสั่ง และคำสั่งของคุณอาจใช้เฉพาะข้อผิดพลาดมาตรฐานเป็นเอาต์พุตเท่านั้น คุณสามารถตรวจสอบได้ทั้งสองอย่าง:

def process = cmd.execute()
def stdOut = process.inputStream.text
def stdErr = process.errorStream.text
person Jonatan Ivanov    schedule 17.08.2018
comment
ใน Jenkinsfile แบบดั้งเดิม ใช่แล้ว สิ่งนี้จะได้ผล :) แต่ฉันทำงานกับ Jenkins Shared Libraries และเชลล์สคริปต์กำลังถูกเรียกจากไลบรารี - person ; 17.08.2018
comment
อ๊ะ ขออภัย ฉันเข้าใจผิดปัญหา โปรดตรวจสอบคำตอบที่อัปเดตของฉัน - person Jonatan Ivanov; 26.08.2018
comment
ฉันประสบปัญหาเดียวกันกับ Process ที่พยายามดำเนินการคำสั่ง curl ฉันจำเป็นต้องกำจัดหรือไม่? stackoverflow .com/questions/56574053/ - person SSF; 13.06.2019