AS400_API_DOTNET/Jenkinsfile

192 lines
6.1 KiB
Groovy

pipeline {
agent any
options {
ansiColor('xterm')
timestamps()
}
environment {
// ถ้าใช้ local bare repo
GIT_URL = 'file:///repos/AS400API.git'
// Path ติดตั้ง dotnet ชั่วคราวใน pipeline
DOTNET_ROOT = "${WORKSPACE}/.dotnet"
PATH = "${DOTNET_ROOT}:${PATH}"
// Dependency-Check cache (แมพกับ volume/โฟลเดอร์บน Jenkins)
DC_DATA = "${JENKINS_HOME}/.dc-cache"
// ถ้าจะใช้ SonarQube ให้ตั้งค่าตามระบบจริง
// SONAR_HOST_URL = 'http://sonarqube:9000'
// SONAR_TOKEN = credentials('SONAR_TOKEN')
}
stages {
stage('Checkout') {
steps {
checkout([$class: 'GitSCM',
branches: [[name: '*/main']],
userRemoteConfigs: [[url: "${GIT_URL}"]]
])
}
}
stage('Install prerequisites') {
steps {
sh '''
set -euo pipefail
if command -v apt-get >/dev/null 2>&1; then
export DEBIAN_FRONTEND=noninteractive
apt-get update
apt-get install -y --no-install-recommends \
ca-certificates curl unzip jq git openjdk-21-jre-headless
fi
mkdir -p "${DOTNET_ROOT}"
curl -fsSL https://dot.net/v1/dotnet-install.sh -o dotnet-install.sh
bash dotnet-install.sh --channel 9.0 --install-dir "${DOTNET_ROOT}"
dotnet --info
# เตรียม cache สำหรับ Dependency-Check
mkdir -p "${DC_DATA}"
'''
}
}
stage('SCA (NuGet + OWASP)') {
steps {
sh '''
set -euo pipefail
echo "=== NuGet vulnerability audit ==="
dotnet restore
dotnet list package --vulnerable || true
echo "=== OWASP Dependency-Check ==="
rm -rf depcheck
mkdir -p depcheck
API="https://api.github.com/repos/jeremylong/DependencyCheck/releases/latest"
echo "Resolving latest Dependency-Check..."
ASSET_URL=$(curl -fsSL "$API" | jq -r '.assets[]?.browser_download_url | select(test("release\\\\.zip$"))' | head -n1)
echo "Downloading: $ASSET_URL"
curl -fL --retry 3 --retry-all-errors -o depcheck.zip "$ASSET_URL"
unzip -q depcheck.zip -d dependency-check
DC_BIN="dependency-check/dependency-check/bin/dependency-check.sh"
# อัปเดตฐานข้อมูลครั้งแรก (และทุกครั้งที่ cache ว่าง)
bash "$DC_BIN" --data "${DC_DATA}" --updateonly || true
# สแกนจริง (เร็ว เพราะใช้ cache)
bash "$DC_BIN" -f HTML -f XML \
--project "AS400API" \
--scan . \
--out depcheck \
--data "${DC_DATA}" \
--noupdate || true
'''
}
post {
always {
archiveArtifacts artifacts: 'depcheck/**', allowEmptyArchive: true
// ถ้ามี HTML Publisher plugin จะโชว์รายงานสวยขึ้น
publishHTML(target: [
reportName: 'OWASP Dependency-Check',
reportDir: 'depcheck',
reportFiles: 'dependency-check-report.html',
keepAll: true,
alwaysLinkToLastBuild: true,
allowMissing: true
])
}
}
}
stage('SAST') {
steps {
sh '''
set -euo pipefail
if [ -n "${SONAR_HOST_URL:-}" ] && [ -n "${SONAR_TOKEN:-}" ]; then
echo "=== SAST with SonarQube ==="
# ถ้าใช้ sonarscanner for .NET (แนะนำ)
dotnet tool update --global dotnet-sonarscanner || dotnet tool install --global dotnet-sonarscanner
export PATH="$HOME/.dotnet/tools:${PATH}"
dotnet-sonarscanner begin \
/k:"AS400API" \
/d:sonar.host.url="${SONAR_HOST_URL}" \
/d:sonar.login="${SONAR_TOKEN}"
dotnet build -c Release
dotnet-sonarscanner end /d:sonar.login="${SONAR_TOKEN}"
else
echo "=== SAST with Roslyn analyzers (no Sonar) ==="
# เปิด .NET analyzers และ treat warnings เป็น error
dotnet build -c Release \
-p:EnableNETAnalyzers=true \
-p:TreatWarningsAsErrors=true \
-warnaserror
fi
'''
}
}
stage('Test + Coverage') {
steps {
sh '''
set -euo pipefail
# รันเทส + สร้างผลลัพธ์ JUnit XML + Coverage (Cobertura)
dotnet test \
--logger "junit;LogFileName=test-results.xml" \
/p:CollectCoverage=true \
/p:CoverletOutput=coverage/ \
/p:CoverletOutputFormat=cobertura
# รวม coverage ไว้ที่เดียวเพื่อ publish/เก็บ artifacts
mkdir -p coverage-report
COB=$(find . -type f -name "coverage.cobertura.xml" | head -n1 || true)
if [ -n "$COB" ]; then
cp "$COB" coverage-report/Cobertura.xml
fi
'''
}
post {
always {
// รายงานผลเทส (JUnit)
junit allowEmptyResults: false, testResults: '**/TestResults/**/*.xml'
// เก็บไฟล์ coverage
archiveArtifacts artifacts: 'coverage-report/**', allowEmptyArchive: true
// (ทางเลือก) ถ้าติดตั้ง Coverage plugin
// publishCoverage adapters: [coberturaAdapter('coverage-report/Cobertura.xml')], sourceFileResolver: sourceFiles('STORE_LAST_BUILD')
}
}
}
stage('Build') {
steps {
sh '''
set -euo pipefail
dotnet publish -c Release -o out
'''
}
post {
success {
archiveArtifacts artifacts: 'out/**', allowEmptyArchive: false
}
}
}
}
post {
always {
echo "Pipeline finished (status: ${currentBuild.currentResult})"
}
}
}