From 10c2f73587793bc55516fc6bbeb0c91e473e6666 Mon Sep 17 00:00:00 2001 From: duynguyen Date: Sun, 26 Apr 2026 13:43:49 +0700 Subject: [PATCH] first commit --- vars/bumpHelmChart.groovy | 26 ++++++++++++++++++++++ vars/dockerBuildPush.groovy | 41 +++++++++++++++++++++++++++++++++++ vars/gitCommitPush.groovy | 40 ++++++++++++++++++++++++++++++++++ vars/homelabK8sAgent.groovy | 43 +++++++++++++++++++++++++++++++++++++ vars/runNodeTest.groovy | 17 +++++++++++++++ 5 files changed, 167 insertions(+) create mode 100644 vars/bumpHelmChart.groovy create mode 100644 vars/dockerBuildPush.groovy create mode 100644 vars/gitCommitPush.groovy create mode 100644 vars/homelabK8sAgent.groovy create mode 100644 vars/runNodeTest.groovy diff --git a/vars/bumpHelmChart.groovy b/vars/bumpHelmChart.groovy new file mode 100644 index 0000000..20df3aa --- /dev/null +++ b/vars/bumpHelmChart.groovy @@ -0,0 +1,26 @@ +/** + * Bumps the patch version in Chart.yaml, updates appVersion and values.yaml image tag. + * Must be called inside container('tools') block (needs sed + git). + * + * config keys: + * imageTag (required) - new image tag to write into values.yaml + * chartFile (optional) - path to Chart.yaml, default: manifest/helm/Chart.yaml + * valuesFile (optional) - path to values.yaml, default: manifest/helm/values.yaml + */ +def call(Map config) { + def imageTag = config.imageTag + if (!imageTag) error('bumpHelmChart: imageTag is required') + + def chartFile = config.chartFile ?: 'manifest/helm/Chart.yaml' + def valuesFile = config.valuesFile ?: 'manifest/helm/values.yaml' + + def content = readFile(chartFile) + def matcher = content =~ /version:\s+(\d+)\.(\d+)\.(\d+)/ + if (!matcher) error("bumpHelmChart: could not parse version in ${chartFile}") + + def newVersion = "${matcher[0][1]}.${matcher[0][2]}.${(matcher[0][3] as int) + 1}" + + sh "sed -i 's/^version: .*/version: ${newVersion}/' ${chartFile}" + sh "sed -i 's/^appVersion: .*/appVersion: \"${imageTag}\"/' ${chartFile}" + sh "sed -i 's/^ tag: .*/ tag: ${imageTag}/' ${valuesFile}" +} diff --git a/vars/dockerBuildPush.groovy b/vars/dockerBuildPush.groovy new file mode 100644 index 0000000..3f9aa62 --- /dev/null +++ b/vars/dockerBuildPush.groovy @@ -0,0 +1,41 @@ +/** + * Logs in to Harbor, builds and pushes a Docker image. + * Must be called inside container('docker') block. + * Returns the full image tag used (e.g. "main-a1b2c3d4"). + * + * config keys: + * appName (required) - image name, e.g. 'tictactoe' + * registry (optional) - Harbor internal service, default: harbor-core.harbor.svc.cluster.local + * project (optional) - Harbor project, default: library + * credId (optional) - Jenkins credential id, default: harbor-credentials + * tag (optional) - image tag; auto-generated as - if not set + * dockerfile(optional) - path to Dockerfile, default: Dockerfile + * context (optional) - Docker build context, default: . + */ +def call(Map config) { + def appName = config.appName + if (!appName) error('dockerBuildPush: appName is required') + + def registry = config.registry ?: 'harbor-core.harbor.svc.cluster.local' + def project = config.project ?: 'library' + def credId = config.credId ?: 'harbor-credentials' + def dockerfile = config.dockerfile ?: 'Dockerfile' + def context = config.context ?: '.' + def tag = config.tag ?: "${env.BRANCH_NAME.replaceAll('/', '-')}-${UUID.randomUUID().toString().take(8)}" + + def fullImage = "${registry}/${project}/${appName}" + + withCredentials([usernamePassword( + credentialsId: credId, + usernameVariable: 'HARBOR_USER', + passwordVariable: 'HARBOR_PASS' + )]) { + sh """ + docker login ${registry} -u \${HARBOR_USER} -p \${HARBOR_PASS} + docker build -f ${dockerfile} -t ${fullImage}:${tag} ${context} + docker push ${fullImage}:${tag} + """ + } + + return tag +} diff --git a/vars/gitCommitPush.groovy b/vars/gitCommitPush.groovy new file mode 100644 index 0000000..2b95a36 --- /dev/null +++ b/vars/gitCommitPush.groovy @@ -0,0 +1,40 @@ +/** + * Commits specified files and pushes to the remote Git repo. + * Must be called inside container('tools') block (needs git). + * + * config keys: + * files (required) - list of file paths to stage, e.g. ['manifest/helm/Chart.yaml', 'manifest/helm/values.yaml'] + * message (required) - commit message + * credId (optional) - Jenkins credential id for Gitea, default: gitea-credentials + * email (optional) - git author email, default: jenkins@fireflylab.local + * name (optional) - git author name, default: Jenkins + */ +def call(Map config) { + def files = config.files + def message = config.message + if (!files) error('gitCommitPush: files is required') + if (!message) error('gitCommitPush: message is required') + + def credId = config.credId ?: 'gitea-credentials' + def email = config.email ?: 'jenkins@fireflylab.local' + def name = config.name ?: 'Jenkins' + + def fileList = (files instanceof List) ? files.join(' ') : files + + withCredentials([usernamePassword( + credentialsId: credId, + usernameVariable: 'GIT_USER', + passwordVariable: 'GIT_PASS' + )]) { + sh """ + git config user.email "${email}" + git config user.name "${name}" + git add ${fileList} + git commit -m "${message}" + REMOTE_URL=\$(git remote get-url origin) + AUTH_URL=\$(echo \$REMOTE_URL | sed "s|https://|https://\${GIT_USER}:\${GIT_PASS}@|") + BRANCH=\$(git rev-parse --abbrev-ref HEAD) + git push \$AUTH_URL HEAD:\$BRANCH + """ + } +} diff --git a/vars/homelabK8sAgent.groovy b/vars/homelabK8sAgent.groovy new file mode 100644 index 0000000..1b9b686 --- /dev/null +++ b/vars/homelabK8sAgent.groovy @@ -0,0 +1,43 @@ +/** + * Returns a K8s pod YAML string for use in agent { kubernetes { yaml ... } } + * + * config keys (all optional): + * nodeImage - default: node:18-slim + * harborRegistry - default: harbor-core.harbor.svc.cluster.local + * withTools - include alpine/git container, default: false + */ +def call(Map config = [:]) { + def nodeImage = config.nodeImage ?: 'node:18-slim' + def harborReg = config.harborRegistry ?: 'harbor-core.harbor.svc.cluster.local' + def withTools = config.withTools ?: false + + def toolsBlock = withTools ? """ + - name: tools + image: alpine/git + command: + - sleep + args: + - infinity""" : "" + + return """ +apiVersion: v1 +kind: Pod +spec: + containers: + - name: node + image: ${nodeImage} + command: + - sleep + args: + - infinity + - name: docker + image: docker:dind + securityContext: + privileged: true + env: + - name: DOCKER_TLS_CERTDIR + value: "" + args: + - --insecure-registry=${harborReg}${toolsBlock} +""".stripIndent() +} diff --git a/vars/runNodeTest.groovy b/vars/runNodeTest.groovy new file mode 100644 index 0000000..6cc8133 --- /dev/null +++ b/vars/runNodeTest.groovy @@ -0,0 +1,17 @@ +/** + * Runs npm install + npm test inside current container. + * Must be called inside container('node') block. + * + * config keys (all optional): + * workDir - directory to run in, default: '.' + * testCmd - npm script to run, default: 'test' + */ +def call(Map config = [:]) { + def workDir = config.workDir ?: '.' + def testCmd = config.testCmd ?: 'test' + + dir(workDir) { + sh 'npm install' + sh "npm ${testCmd}" + } +}