我正在将代码从 Jenkins 迁移到 GitHub Actions。我在 Jenkins 中的代码已经投入生产。
我的管道有什么作用?
读取 GitHub 上的
Config.json
文件。
在脚本中,它根据
Config.json
中的值初始化所有变量、数组、对象。
根据条件触发一系列 cURL 命令。
我打算做什么?
我不想为 GitHub Actions 重新发明轮子,而是想通过执行
script {}
中的 script.groovy
来重用 GitHub Actions 中 Jenkins 的 migrateToGitHubActions.yaml
代码。
script.groovy
具有来自 Jenkins 管道的 script {}
的确切代码。
来自我的詹金斯:
pipeline{
agent any
stages{
stage('Start'){
steps{
sh 'ls'
}
}
stage('Clone Repo'){
steps{
git credentialsId: 'githubapp', url: 'https://github.com/configurations.git', branch: "${env}"
}
}
stage('Configure'){
steps{
script{
sh 'cat Config.json'
def configs = readJSON(file: 'Config.json')
def totalBundles = configs.bundles.size()
println "Total Array Size =" + totalBundles
def productName = new Object[totalBundles]
....
}
}
}
}
}
配置.json:
{
"bundles":
[
{
"product":{
"name" : "Product1",
"proxies" : ["'Proxy1', 'Proxy2'"],
"attributes" : [{"name":"Test1","value":"abc"}]
},
"app":{
"name":"App1",
"attributes": [{"name": "attribute1","value": "null"}],
"developer": "[email protected]"
}
},
{
"product":{
"name" : "Product2",
"proxies" : ["'Proxy1', 'Proxy2'"],
"attributes" : [{"name":"Test2","value":"xyz"}]
},
"app":{
"name":"App1",
"attributes": [{"name": "attribute2","value": "null"}],
"developer": "[email protected]"
}
}
]
}
我的 GitHub Actions migrateToGitHubActions.yaml:
name: Config
on:
workflow_dispatch:
jobs:
build:
runs-on: [abc]
steps:
- name: Checkout repository
uses: actions/checkout@v3
- name: List files (Start)
run: |
ls
- name: Set up JDK 11
uses: actions/setup-java@v3
with:
java-version: '11'
distribution: 'adopt'
- name: Install Groovy
run: sudo apt-get update && sudo apt-get install -y groovy
- name: Run Groovy script
run: groovy script.groovy
script.groovy:
#!/usr/bin/env groovy
import groovy.json.JsonSlurper
println "*** Before Read ***"
// Reading JSON from file
def jsonFile = new File('AppsProductsConfig.json')
def configs = new JsonSlurper().parseText(jsonFile.text)
println "configs = $configs"
println "*** After Read ***"
def totalBundles = configs.bundles.size()
println "Total Array Size = $totalBundles"
// Initialization of arrays
def productName = new String[totalBundles]
def developer = new String[totalBundles]
def firstName = new String[totalBundles]
def lastName = new String[totalBundles]
def userName = new String[totalBundles]
def approvalType = new String[totalBundles]
def productAttributeName = new String[totalBundles]
def productAttributeValue = new String[totalBundles]
def displayName = new String[totalBundles]
def environments = new String[totalBundles]
def proxies = new Object[totalBundles][]
def appName = new String[totalBundles]
def appAttributeName = new String[totalBundles]
def appAttributeValue = new String[totalBundles]
def host = "example.com"
def USER = System.getenv('USER')
println "*** After Initialisation Read ***"
// Extract and Store Values
println "**** Read Variables ***"
for (int i = 0; i < totalBundles; i++) {
def bundle = configs.bundles[i]
// Products
productName[i] = bundle.product.name
approvalType[i] = "auto"
productAttributeName[i] = bundle.product.attributes[0].name
productAttributeValue[i] = bundle.product.attributes[0].value
displayName[i] = bundle.product.name
environments[i] = System.getenv('env') // Assuming 'env' is an environment variable
proxies[i] = bundle.product.proxies
// Developer
developer[i] = bundle.app.developer
firstName[i] = developer[i].takeWhile { it != '.' }
def start = developer[i].indexOf(".") + 1
def end = developer[i].indexOf("@")
lastName[i] = developer[i].substring(start, end).replaceAll(/[^a-zA-Z]/, "")
userName[i] = developer[i].takeWhile { it != '@' }
// Apps
appName[i] = bundle.app.name
appAttributeName[i] = bundle.app.attributes[0].name
appAttributeValue[i] = bundle.app.attributes[0].value
println "*** Print Apps & Products ***"
println "Product Name = $productName[i]"
println "App Name = $appName[i]"
println "Approval Type = $approvalType[i]"
println "Product Attributes Name = $productAttributeName[i]"
println "Product Attributes Value = $productAttributeValue[i]"
println "Display Name = $displayName[i]"
println "Environments = $environments[i]"
println "Proxies = ${proxies[i]}"
println "Developer = $developer[i]"
println "App Attributes Name = $appAttributeName[i]"
println "App Attributes Value = $appAttributeValue[i]"
}
for (int i = 0; i < totalBundles; i++) {
def productBody = """{
"approvalType": "${approvalType[i]}",
"attributes": [{"name": "${productAttributeName[i]}", "value": "${productAttributeValue[i]}"}],
"displayName": "${displayName[i]}",
"environments": ["${environments[i]}"],
"name": "${productName[i]}",
"proxies": ${proxies[i]}
}"""
println "Product Body = $productBody"
def developerBody = """{
"email": "${developer[i]}",
"firstName": "${firstName[i]}",
"lastName": "${lastName[i]}",
"userName": "${userName[i]}"
}"""
println "Developer Body = $developerBody"
def appBody = """{
"name": "${appName[i]}",
"apiProducts": ["${productName[i]}"],
"attributes": [{"name": "${appAttributeName[i]}", "value": "${appAttributeValue[i]}"}],
"keyExpiresIn": "31536000000"
}"""
println "App Body = $appBody"
// Products
def createProductResponse = sh(script: "curl -k -s -w '\\n%{response_code}' --header 'Authorization:Basic $USER' --header 'Content-Type: application/json' --data-binary '$productBody' --request POST https://${host}/apiproducts", returnStdout: true).trim()
println "$createProductResponse"
if (createProductResponse.contains('201')) {
println "*** Product ${productName[i]} created successfully ***"
} else if (createProductResponse.contains('409')) {
def updateProductResponse = sh(script: "curl -k -s -w '\\n%{response_code}' --header 'Authorization:Basic $USER' --header 'Content-Type: application/json' --data-binary '$productBody' --request PUT https://${host}/apiproducts/${productName[i]}", returnStdout: true).trim()
println "$updateProductResponse"
if (updateProductResponse.contains('200')) {
println "*** Product ${productName[i]} updated successfully ***"
} else {
error "Failed to update ${productName[i]} with $updateProductResponse"
}
} else {
error "Failed to create ${productName[i]} with $createProductResponse"
}
// Developers
def createDeveloperResponse = sh(script: "curl -k -s -w '\\n%{response_code}' --header 'Authorization:Basic $USER' --header 'Content-Type: application/json' --data-binary '$developerBody' --request POST https://${host}/developers", returnStdout: true).trim()
println "$createDeveloperResponse"
if (createDeveloperResponse.contains('201')) {
println "*** Developer ${developer[i]} created successfully ***"
} else if (createDeveloperResponse.contains('409')) {
println "*** Developer already exists: $createDeveloperResponse ***"
} else {
error "Failed to create ${developer[i]} with $createDeveloperResponse"
}
// Apps
def createAppResponse = sh(script: "curl -k -s -w '\\n%{response_code}' --header 'Authorization:Basic $USER' --header 'Content-Type: application/json' --data-binary '$appBody' --request POST https://${host}/developers/${developer[i]}/apps", returnStdout: true).trim()
println "$createAppResponse"
if (createAppResponse.contains('201')) {
println "*** App ${appName[i]} created successfully ***"
} else if (createAppResponse.contains('409')) {
def updateAppBody = """{
"attributes": [{"name": "${appAttributeName[i]}", "value": "${appAttributeValue[i]}"}]
}"""
println "Updated App Body = $updateAppBody"
def updateAppResponse = sh(script: "curl -k -s -w '\\n%{response_code}' --header 'Authorization:Basic $USER' --header 'Content-Type: application/json' --data-binary '$updateAppBody' --request PUT https://${host}/developers/${developer[i]}/apps/${appName[i]}", returnStdout: true).trim()
println "$updateAppResponse"
if (updateAppResponse.contains('200')) {
println "*** App ${appName[i]} updated successfully ***"
} else {
error "Failed to update ${appName[i]} with $updateAppResponse"
}
} else {
error "Failed to create ${appName[i]} with $createAppResponse"
}
}
文件夹结构:
运行 migrateToGitHubActions.yaml 时,大多数行都遇到错误
GitHub Actions 的脚本编写能力比 Jenkins 少吗? Actions 中需要什么样的脚本?
错误:
警告:发生了非法反射访问操作警告: 非法反射访问 org.codehaus.groovy.reflection.CachedClass (文件:/usr/share/groovy/lib/groovy-2.4.17.jar)到方法 java.lang.Object.finalize() 警告:请考虑将此报告给 org.codehaus.groovy.reflection.CachedClass 的维护者警告: 使用 --illegal-access=warn 启用进一步非法的警告 反射访问操作警告:所有非法访问操作 将在未来版本中被拒绝 捕获: groovy.lang.MissingPropertyException:没有这样的属性:json for 类:java.io.File groovy.lang.MissingPropertyException:没有这样的 属性:类的 json:java.io.File at script.run(script.groovy:3) 在 java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(本机 方法)在 java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 在 java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 错误:进程已完成,退出代码为 1。
我已经测试了您的工作流程配置,您面临的问题似乎与 groovy 脚本有关。
经过一些研究(以及 Chat GPT 使用),我发现您在 Jenkins 中使用的一些命令行无法直接在 Github Actions 上使用。
示例:
sh
命令仅在 Jenkins 上可用,您应该在 groovy 脚本中将此命令行替换为 execute
,然后在工作流中运行脚本时此操作应该起作用。
此外,我要求聊天 GPT 更正您共享的 groovy 脚本的第一个版本(我对 groovy 不熟悉),并通过使用此 工作流文件 让工作流程正常工作 here - 更新一些操作版本 - 以及这个更新的 Groovy 脚本。
注意:如果您在 groovy 脚本方面遇到更多问题,我建议您在 StackOverflow 上使用
groovy
标签提出另一个问题,以便 groovy 社区给出更详细的答案。