// New entry point — the homelab equivalent of the real devops-lib's // buildPipeline.groovy. Same shape: a scripted pipeline global, so a // service Jenkinsfile needs nothing but `@Library('devops-lib') _` plus // one call to this — no pipeline{}/agent{}/stages{} block in the // consuming repo at all, matching gkeCICD.groovy's Podcall precedent // (podTemplate { node(POD_LABEL) { ... } }) rather than the declarative // style the earlier version of this Jenkinsfile template used. // // Only repo_name is required — everything else defaults sensibly for a // single-service repo on this one homelab cluster. Override any key by // passing it explicitly, same as the real buildPipeline's param map, or // by committing a config.yaml to the repo root (loadConfig merges it in // after checkout — repo-committed values win over these defaults, same // as the real system's config.yaml). // // dockerBuildVersion (e.g. 'go-1.22', 'node-20', 'python-3.12', 'java-21', // 'php-8.3') is read by buildDocker.groovy only when the repo has no // Dockerfile of its own — it picks which resources/com/homelab/- // Dockerfile template to render and which base-image version to bake in. // Repos that already ship a Dockerfile (like demo-go-app) never touch // this key at all; it has no default because there's no sensible one to // fall back to. def call(Map config) { config.service_name = config.service_name ?: config.repo_name config.argo_app_name = config.argo_app_name ?: config.repo_name // The Harbor project images are pushed to. Named apps-registry on this // cluster, not the homelab's "homelab" — the project has to already // exist, and Harbor rejects a push to a missing one with // "unauthorized: project not found", which reads like a // credentials problem rather than a missing project. config.harbor_project = config.harbor_project ?: 'apps-registry' // Cluster DNS, not the ingress hostname: this clone happens from a build // pod, so it is pod-to-pod traffic and has no business leaving the // cluster and coming back in through Contour. config.helm_repo_url = config.helm_repo_url ?: 'http://gitea-http.gitea.svc.cluster.local:3000/gitadmin/devops-helm-charts-gcp.git' config.image_tag_yq_path = config.image_tag_yq_path ?: '.deployment.image.tag' // Every stage file (both the ones adapted for this homelab and the // untouched legacy ones carried over from the real devops-lib) reads // `env.FAILURE` when setting currentBuild.result on error — the real // system must define this as a global Jenkins environment variable // somewhere upstream of buildPipeline.groovy, since it's referenced // everywhere but never set anywhere in this repo. Left undefined, // `env.FAILURE` is null, and `currentBuild.result = null` throws // `NoSuchMethodError`/`NullPointerException` deep inside Jenkins' // own result-normalization code — masking whatever the real error // was. Defining it once here, before any stage runs, is the minimal // fix rather than touching every individual stage file. env.FAILURE = 'FAILURE' podTemplate(yaml: libraryResource('org/homelab/dind-pod.yaml')) { node(POD_LABEL) { def checkOutObj = new com.homelab.stages.checkOut() def loadConfigObj = new com.homelab.stages.loadConfig() def runHooksObj = new com.homelab.stages.runHooks() def buildDockerObj = new com.homelab.stages.buildDocker() def updateHelmTagObj = new com.homelab.stages.updateHelmTag() def syncArgoAppObj = new com.homelab.stages.syncArgoApp() def notifyObj = new com.homelab.stages.notify() try { checkOutObj.run(config) loadConfigObj.run(config) runHooksObj.run(config, 'pre_build') buildDockerObj.run(config) runHooksObj.run(config, 'post_build') updateHelmTagObj.run(config) syncArgoAppObj.run(config) } catch (Exception e) { currentBuild.result = 'FAILURE' log.error(e.toString()) } finally { notifyObj.run(config) } } } }