commit efed96875f3405a50e1ef0069bb9d0b7b283aa02 Author: Mukul Sharma Date: Wed Sep 2 01:38:16 2026 +0530 add demo app diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..fa9393d --- /dev/null +++ b/Dockerfile @@ -0,0 +1,10 @@ +FROM golang:1.22-alpine AS build +WORKDIR /src +COPY go.mod ./ +COPY main.go ./ +RUN CGO_ENABLED=0 go build -o /app . + +FROM alpine:3.20 +COPY --from=build /app /app +EXPOSE 8080 +ENTRYPOINT ["/app"] diff --git a/Jenkinsfile b/Jenkinsfile new file mode 100644 index 0000000..087ab6a --- /dev/null +++ b/Jenkinsfile @@ -0,0 +1,2 @@ +@Library('devops-lib') _ +homelabPipeline(repo_name: 'demo-go-app') diff --git a/config.yaml b/config.yaml new file mode 100644 index 0000000..3340772 --- /dev/null +++ b/config.yaml @@ -0,0 +1,16 @@ +# Read by devops-lib's loadConfig stage after checkout — merges into the +# pipeline's config map, overriding whatever homelabPipeline(repo_name: ...) +# passed in the Jenkinsfile. Everything here is optional; this file exists +# mainly to prove the hooks mechanism actually runs, not because this app +# needs to override any of the pipeline defaults. +hooks: + pre_build: + - name: gofmt-check + script: scripts/pre-build-check.sh + # Advisory on purpose for this demo — a real repo would probably + # want this blocking (the default), but failing the one demo app + # over a formatting nit isn't the point here. + blocking: false + post_build: + - name: report-tag + script: scripts/post-build-notify.sh diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..027bf5b --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module demo-go-app + +go 1.22 diff --git a/main.go b/main.go new file mode 100644 index 0000000..61fa974 --- /dev/null +++ b/main.go @@ -0,0 +1,37 @@ +package main + +import ( + "fmt" + "log" + "net/http" + "os" +) + +func main() { + // Read from the environment, not baked in at build time — the Helm + // chart's deployment.env sets APP_VERSION from the same image tag + // updateHelmTag.groovy just bumped, so curling /version proves the + // whole CI/CD loop (build -> push -> tag-bump -> deploy) actually + // worked end to end, not just that "some" image is running. + version := os.Getenv("APP_VERSION") + if version == "" { + version = "dev" + } + http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintf(w, "hello from demo-go-app, version %s\n", version) + }) + http.HandleFunc("/health", func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + fmt.Fprintln(w, "ok") + }) + http.HandleFunc("/version", func(w http.ResponseWriter, r *http.Request) { + fmt.Fprintln(w, version) + }) + + port := os.Getenv("PORT") + if port == "" { + port = "8080" + } + log.Printf("listening on :%s (version %s)", port, version) + log.Fatal(http.ListenAndServe(":"+port, nil)) +} diff --git a/scripts/post-build-notify.sh b/scripts/post-build-notify.sh new file mode 100755 index 0000000..280cf9a --- /dev/null +++ b/scripts/post-build-notify.sh @@ -0,0 +1,5 @@ +#!/bin/sh +# Proves HOOK_IMAGE_TAG is actually populated post-build (empty during +# pre_build, since buildDocker hasn't set env.TAG yet at that point). +set -e +echo "post_build hook: ${HOOK_REPO} built and pushed as tag ${HOOK_IMAGE_TAG}" diff --git a/scripts/pre-build-check.sh b/scripts/pre-build-check.sh new file mode 100755 index 0000000..1c0ae22 --- /dev/null +++ b/scripts/pre-build-check.sh @@ -0,0 +1,10 @@ +#!/bin/sh +# Runs in the docker-cli container (Alpine, no Go toolchain — the actual +# Go build happens inside the Dockerfile's golang:1.22-alpine builder +# stage, not on the agent itself). Kept simple on purpose: this exists to +# prove the hooks mechanism runs, not to be a real lint step. +set -e +echo "pre_build hook running for ${HOOK_REPO} (phase=${HOOK_PHASE})" +test -f go.mod || { echo "go.mod missing"; exit 1; } +test -f Dockerfile || { echo "Dockerfile missing"; exit 1; } +echo "go.mod and Dockerfile both present — looks buildable."