Mukul SharmaandClaude Opus 5 43ca78e83e buildDocker: fail fast with a specific message when the repo doesn't match the fallback's assumed layout
Every fallback template (go/node/python/java) assumes one fixed repo
layout — a root go.mod, a root package.json, requirements.txt, a root
pom.xml. Without this, a repo shaped any other way failed inside
`docker build`'s COPY step with a raw "file not found" error that never
said which file the fallback expected or why, several minutes into a
build someone was told needs no Dockerfile at all (testing1 hit exactly
this: no go.mod, "COPY failed: file not found in build context: go.mod").

validateRepoStructure checks for the one file each language's template
actually requires before rendering it, and errors with the file name,
what it's for, and the escape hatch (bring your own Dockerfile, which
always wins over this fallback regardless of layout).

This does not make the fallback dynamic — it is still one fixed layout
per language. It only turns a silent wrong assumption into a message
that says what the assumption was. Real detection across arbitrary repo
layouts is Cloud Native Buildpacks' job, tracked as its own step in
toolshed's docs/PRODUCT-ARCHITECTURE.md.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Wajog7nELA3i8JWTjxYGHF
2026-09-05 22:08:13 +05:30

devops-lib

Jenkins Shared Library for this homelab's CI/CD pipeline. Adapted from a much larger, company-wide library — everything not needed for a single-node homelab (GKE/EKS, JFrog, S3, Sonar, org-specific BU/team validation, and ~65 other files covering languages/deploy-targets this setup never uses) has been removed rather than carried along unused; see git history if any of that is ever worth reviving.

Using it in a service repo

The entire Jenkinsfile is 2 lines:

@Library('devops-lib') _
homelabPipeline(repo_name: 'my-service')

repo_name is the only required key. Everything else has a sensible default — override any of them by passing extra keys to homelabPipeline, or by committing a config.yaml to the service repo's own root (merged in after checkout; repo-committed values win over the Jenkinsfile call).

Key Default Notes
service_name repo_name Second path segment under devops-helm-charts/values/
argo_app_name repo_name Must match the ArgoCD Application's metadata.name
harbor_project homelab Must be an existing, public Harbor project
helm_repo_url devops-helm-charts on this Gitea
image_tag_yq_path .deployment.image.tag Override this if the app's chart isn't 1.0.0 — e.g. sts-2.0.0 uses .podtemplate.image.tag instead. Getting this wrong doesn't fail loudly: yq -i creates the path if missing rather than erroring, silently leaving the real field un-bumped.
dockerBuildVersion none Only read when the repo has no Dockerfile of its own — picks a fallback template (see below). No default; either ship a Dockerfile or set this.

Pipeline stages

checkOut → loadConfig → runHooks(pre_build) → buildDocker → runHooks(post_build) → updateHelmTag → syncArgoApp → notify, all inside a podTemplate (resources/org/homelab/dind-pod.yaml) via node(POD_LABEL) { ... }.

  • loadConfig — if the repo has a config.yaml at its root, its keys are merged into the pipeline config (repo values win).
  • runHooks — reads config.yaml's hooks.pre_build/hooks.post_build lists, each {name, script, interpreter, requirements, blocking, timeout_seconds}. Blocking by default; blocking: false demotes a failure to advisory (log + continue). Script paths must be repo-relative (no .., no absolute paths).
  • buildDocker — uses the repo's own Dockerfile if present; otherwise renders one from resources/com/homelab/<lang>-Dockerfile based on dockerBuildVersion (e.g. go-1.22, node-20, python-3.12, java-21, php-8.3). All fallback templates pull base images from Harbor's base-images project (mirrored via the separate devops-base-images repo), not Docker Hub directly.
  • updateHelmTag — clones devops-helm-charts, bumps the image tag via yq at image_tag_yq_path, commits, pushes to main.
  • syncArgoApp — calls the ArgoCD REST API to sync argo_app_name.

Adding a new language's fallback template

  1. Add the base image to devops-base-images/images.txt, re-mirror it into Harbor.
  2. Add resources/com/homelab/<lang>-Dockerfile, parametrized by ${version} (rendered via constructTemplate.groovy's SimpleTemplateEngine wrapper).
  3. Add a case for it in buildDocker.groovy's templates map.

Build-tools image

resources/org/homelab/build-tools.Dockerfile bakes git/yq/bash/ python3+pip/venv/curl into the docker-cli container's image, so nothing gets installed on demand on every single build. Built and pushed manually (not through any Jenkins job) — see that file's own header comment.

S
Description
No description provided
Readme
446 KiB
Languages
Groovy 100%