import groovy.json.JsonSlurper
def resultHtml = '' // 初始化一个变量来存储最终的 HTML
try {
// --- 1. 参数处理 ---
def rawInput = IMAGE_NAME ?: ''
def pureTag = rawInput.split(/\s*\|\s*/)[0].trim()
if (!pureTag) {
resultHtml = '
(请选择镜像 tag)
'
return resultHtml // 立即返回
}
// --- 2. 硬编码凭据 ---
def user = '100038894437' // 你的 TCR 用户名 (UIN)
def pass = 'h8H1o6Fd!HLXn' // 你的 TCR 登录密码
if (!user || !pass) {
resultHtml = '❌ 凭据为空
'
return resultHtml // 立即返回
}
// --- 3. API 查询 ---
final String REG = "https://uswccr.ccs.tencentyun.com"
final String REPO = "lessiesit/flymoon-email"
// 3.1. Token
def auth = "Basic " + "${user}:${pass}".bytes.encodeBase64().toString()
def tokenUrl = new URL("${REG}/service/token?service=uswccr&scope=repository:${REPO}:pull")
def tokenConn = tokenUrl.openConnection()
tokenConn.setRequestProperty("Authorization", auth)
tokenConn.connect()
if (tokenConn.responseCode != 200) {
def errorBody = tokenConn.errorStream?.text ?: "No error body"
resultHtml = "❌ Token 请求失败 (${tokenConn.responseCode}): ${errorBody.take(200)}
"
return resultHtml // 立即返回
}
def tokenJson = new JsonSlurper().parse(tokenConn.inputStream)
def token = tokenJson?.token
if (!token) {
resultHtml = '❌ 无法从响应中获取 Token
'
return resultHtml // 立即返回
}
// 3.2. Manifest
def manifestUrl = new URL("${REG}/v2/${REPO}/manifests/${pureTag}")
def manifestConn = manifestUrl.openConnection()
manifestConn.setRequestProperty("Authorization", "Bearer ${token}")
manifestConn.setRequestProperty("Accept", "application/vnd.docker.distribution.manifest.v2+json")
manifestConn.connect()
if (manifestConn.responseCode != 200) {
if (manifestConn.responseCode == 404) {
resultHtml = "⚠️ Tag '${pureTag}' 不存在
"
return resultHtml // 立即返回
}
def errorBody = manifestConn.errorStream?.text ?: "No error body"
resultHtml = "❌ Manifest 请求失败 (${manifestConn.responseCode}): ${errorBody.take(200)}
"
return resultHtml // 立即返回
}
def manifestJson = new JsonSlurper().parse(manifestConn.inputStream)
def configDigest = manifestJson?.config?.digest
if (!configDigest) {
resultHtml = '❌ Manifest 中无 config.digest
'
return resultHtml // 立即返回
}
// 3.3. Config Blob (Labels)
def blobUrl = new URL("${REG}/v2/${REPO}/blobs/${configDigest}")
def blobConn = blobUrl.openConnection()
blobConn.setRequestProperty("Authorization", "Bearer ${token}")
blobConn.connect()
if (blobConn.responseCode != 200) {
def errorBody = blobConn.errorStream?.text ?: "No error body"
resultHtml = "❌ Config Blob 请求失败 (${blobConn.responseCode}): ${errorBody.take(200)}
"
return resultHtml // 立即返回
}
def configJson = new JsonSlurper().parse(blobConn.inputStream)
def labels = configJson?.config?.Labels ?: [:]
// --- 4. 格式化输出 ---
// 再次确保 labels 是 Map
if (!(labels instanceof Map)) {
labels = [:]
}
resultHtml = "🏷️ Labels for ${pureTag}:
"
if (labels.isEmpty()) {
resultHtml += "(无 Labels)
"
} else {
labels.each { k, v ->
def key = (k != null) ? k.toString() : 'null_key'
def value = (v != null) ? v.toString().replaceAll(/^'|'$/, '') : 'null_value'
resultHtml += "${key}: ${value}
"
}
}
resultHtml += "
"
// ✅ 修复:在 try 块结束前,确保 resultHtml 是字符串
resultHtml = resultHtml.toString()
} catch (Exception e) {
def errorMsg = e.message?.toString() ?: '未知错误'
def errorClass = e.class.simpleName
resultHtml = "🚨 脚本异常: ${errorClass} - ${errorMsg}
"
}
// ✅ 修复:确保在所有路径下,最终返回的都是字符串
return resultHtml.toString()