diff --git a/.github/workflows/auto-update-jenkins-lts.yaml b/.github/workflows/auto-update-jenkins-lts.yaml new file mode 100644 index 00000000..f951950b --- /dev/null +++ b/.github/workflows/auto-update-jenkins-lts.yaml @@ -0,0 +1,72 @@ +name: auto-update-jenkins-lts + +on: + schedule: + - cron: '0 7 * * 0' + workflow_dispatch: + +permissions: + contents: write + pull-requests: write + +jobs: + check-and-update-jenkins-lts: + runs-on: ubuntu-latest + steps: + - name: Check out code + uses: actions/checkout@08c6903cd8c0fde910a37f88322edcfb5dd907a8 # v5 + + - name: Set up env vars + run: | + echo "GO111MODULE=on" >> $GITHUB_ENV + echo "GO_VERSION=v$(sed -n 's/GO_VERSION=//p' config.base.env | tr -d '\n' | tr -d '"')" >> $GITHUB_ENV + echo "KIND_CLUSTER_NAME=$(sed -n 's/KIND_CLUSTER_NAME=//p' config.base.env | tr -d '\n' | tr -d '"')" >> $GITHUB_ENV + echo "GOPATH=/home/runner/go" >> $GITHUB_ENV + + - name: Check if update needed + id: check + run: | + CURRENT=$(sed -n 's/LATEST_LTS_VERSION=//p' config.base.env | tr -d '\n' | tr -d '"') + LATEST=$(curl -s https://www.jenkins.io/changelog-stable/ | grep -oP 'changelog/\K\d+\.\d+\.\d+' | head -1) + + echo "current=$CURRENT" >> $GITHUB_OUTPUT + echo "latest=$LATEST" >> $GITHUB_OUTPUT + + if [ "$CURRENT" != "$LATEST" ]; then + echo "needs_update=true" >> $GITHUB_OUTPUT + else + echo "needs_update=false" >> $GITHUB_OUTPUT + fi + + - name: Prepare go environment + if: steps.check.outputs.needs_update == 'true' + uses: actions/setup-go@44694675825211faa026b3c33043df3e48a5fa00 # v6 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Ensure Golang runtime dependencies + if: steps.check.outputs.needs_update == 'true' + run: make go-dependencies + + - name: Update Jenkins lts version + if: steps.check.outputs.needs_update == 'true' + run: make update-jenkins-lts + + - name: Update Jenkins base plugins + if: steps.check.outputs.needs_update == 'true' + run: make update-plugins + + - name: Run verify + if: steps.check.outputs.needs_update == 'true' + run: make verify + + - name: Create Pull Request + if: steps.check.outputs.needs_update == 'true' + uses: peter-evans/create-pull-request@271a8d0340265f705b14b6d32b9829c1cb33d45e # v7.0.8 + with: + token: ${{ secrets.GITHUB_TOKEN }} + commit-message: "chore: update Jenkins lts version to ${{ steps.check.outputs.latest }}" + title: "chore: update Jenkins lts version to ${{ steps.check.outputs.latest }}" + body: "auto-update Jenkins lts version from ${{ steps.check.outputs.current }} to ${{ steps.check.outputs.latest }}" + branch: auto-update-jenkins-lts-${{ steps.check.outputs.latest }} + delete-branch: true diff --git a/.github/workflows/update-plugins.sh b/.github/workflows/update-plugins.sh new file mode 100755 index 00000000..34d27e4f --- /dev/null +++ b/.github/workflows/update-plugins.sh @@ -0,0 +1,126 @@ +#!/usr/bin/env bash + +set -euo pipefail + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(cd "$SCRIPT_DIR/../../" && pwd)" + +PLUGINS=( + "configuration-as-code" + "git" + "job-dsl" + "kubernetes" + "kubernetes-credentials-provider" + "workflow-aggregator" +) + +version_compare() { + local ver1="$1" + local ver2="$2" + + ver1=$(echo "$ver1" | sed 's/\([0-9.]*\).*/\1/') + ver2=$(echo "$ver2" | sed 's/\([0-9.]*\).*/\1/') + + if [ "$ver1" = "$ver2" ]; then + return 0 + fi + + local sorted=$(printf '%s\n%s' "$ver1" "$ver2" | sort -V) + local first=$(echo "$sorted" | head -n1) + + if [ "$first" = "$ver1" ]; then + return 1 + else + return 2 + fi +} + +fetch_update_center_data() { + local jenkins_version="$1" + local url="https://updates.jenkins.io/update-center.actual.json?version=${jenkins_version}" + local data=$(curl -s -L -f "$url") + + if ! echo "$data" | jq . > /dev/null 2>&1; then + echo "error something happened" >&2 + return 1 + fi + + echo "$data" +} + +find_compatible_version() { + local plugin_id="$1" + local jenkins_version="$2" + local update_data="$3" + local plugin_data=$(echo "$update_data" | jq ".plugins[\"$plugin_id\"]") + local plugin_version=$(echo "$plugin_data" | jq -r '.version') + local compatible_since=$(echo "$plugin_data" | jq -r '.compatibleSinceVersion // empty') + + if [ -n "$compatible_since" ]; then + version_compare "$jenkins_version" "$compatible_since" + local result=$? + if [ $result -eq 1 ]; then + echo "Error: Plugin '$plugin_id' requires Jenkins $compatible_since or newer" >&2 + return 1 + fi + fi + + echo "$plugin_version" +} + +update_go_file() { + local file_path="$1" + local plugin_id="$2" + local new_version="$3" + local dry_run="$4" + + local var_name="" + case "$plugin_id" in + "configuration-as-code") var_name="configurationAsCodePlugin" ;; + "git") var_name="gitPlugin" ;; + "job-dsl") var_name="jobDslPlugin" ;; + "kubernetes") var_name="kubernetesPlugin" ;; + "kubernetes-credentials-provider") var_name="kubernetesCredentialsProviderPlugin" ;; + "workflow-aggregator") var_name="workflowAggregatorPlugin" ;; + esac + + local relative_path=$(realpath --relative-to="$PROJECT_ROOT" "$file_path") + local new_line=" ${var_name} = \"${plugin_id}:${new_version}\"" + + if [ "$dry_run" = "true" ]; then + echo "$relative_path: $plugin_id:$new_version" + else + sed -i "s|^[[:space:]]*${var_name}[[:space:]]*=.*|${new_line}|" "$file_path" + echo "$relative_path: $var_name -> $plugin_id:$new_version" + fi +} + +main() { + if [ $# -lt 1 ]; then + echo "usage: $0 [--dry-run]" >&2 + exit 1 + fi + + local jenkins_version="$1" + local dry_run="false" + + if [ $# -gt 1 ] && [ "$2" = "--dry-run" ]; then + dry_run="true" + fi + + local update_data + if ! update_data=$(fetch_update_center_data "$jenkins_version"); then + exit 1 + fi + + for plugin_id in "${PLUGINS[@]}"; do + local compatible_version + if compatible_version=$(find_compatible_version "$plugin_id" "$jenkins_version" "$update_data"); then + #printf "%-35s %-30s\n" "$plugin_id" "$compatible_version" + update_go_file "$PROJECT_ROOT/pkg/plugins/base_plugins.go" "$plugin_id" "$compatible_version" "$dry_run" + update_go_file "$PROJECT_ROOT/test/e2e/configuration_test.go" "$plugin_id" "$compatible_version" "$dry_run" + fi + done +} + +main "$@" diff --git a/Makefile b/Makefile index 7d4570a9..571fe644 100644 --- a/Makefile +++ b/Makefile @@ -191,6 +191,36 @@ install: ## Installs the executable @echo "+ $@" go install -tags "$(BUILDTAGS)" ${GO_LDFLAGS} $(BUILD_PATH) +.PHONY: update-plugins +update-plugins: ## Update jenkins base plugins + @echo "+ $@" + @JENKINS_VERSION=$$(sed -n 's/LATEST_LTS_VERSION=//p' config.base.env | tr -d '\n' | tr -d '"'); \ + echo "updating plugins for Jenkins $$JENKINS_VERSION"; \ + ./.github/workflows/update-plugins.sh "$$JENKINS_VERSION" + +.PHONY: update-plugins-dry-run +update-plugins-dry-run: ## Update jenkins base plugin -- dry run + @echo "+ $@" + @JENKINS_VERSION=$$(sed -n 's/LATEST_LTS_VERSION=//p' config.base.env | tr -d '\n' | tr -d '"'); \ + echo "checking plugins for Jenkins $$JENKINS_VERSION -- dry run"; \ + ./.github/workflows/update-plugins.sh "$$JENKINS_VERSION" --dry-run + +.PHONY: update-jenkins-lts +update-jenkins-lts: ## Fetch latest Jenkins lts version and update if necessary + @echo "+ $@" + @LATEST_VERSION=$$(curl -s https://www.jenkins.io/changelog-stable/ | grep -oP 'changelog/\K\d+\.\d+\.\d+' | head -1); \ + CURRENT_VERSION=$$(sed -n 's/LATEST_LTS_VERSION=//p' config.base.env | tr -d '\n' | tr -d '"'); \ + echo "current version: $$CURRENT_VERSION"; \ + echo "latest version: $$LATEST_VERSION"; \ + if [ "$$CURRENT_VERSION" != "$$LATEST_VERSION" ]; then \ + echo "updating Jenkins lts version from $$CURRENT_VERSION to $$LATEST_VERSION"; \ + sed -i "s/LATEST_LTS_VERSION=\".*\"/LATEST_LTS_VERSION=\"$$LATEST_VERSION\"/" config.base.env; \ + $(MAKE) update-lts-version LATEST_LTS_VERSION=$$LATEST_VERSION; \ + echo "updated Jenkins LTS version to $$LATEST_VERSION"; \ + else \ + echo "up to date"; \ + fi + .PHONY: update-lts-version update-lts-version: ## Update the latest lts version @echo "+ $@" diff --git a/chart/jenkins-operator/values.yaml b/chart/jenkins-operator/values.yaml index 47453c67..05ac5610 100644 --- a/chart/jenkins-operator/values.yaml +++ b/chart/jenkins-operator/values.yaml @@ -36,7 +36,7 @@ jenkins: # image is the name (and tag) of the Jenkins instance # Default: jenkins/jenkins:lts # It's recommended to use LTS (tag: "lts") version - image: jenkins/jenkins:2.492.3-lts + image: jenkins/jenkins:2.516.3-lts # env contains jenkins container environment variables env: [] diff --git a/config.base.env b/config.base.env index 508d3890..0bbc63ea 100644 --- a/config.base.env +++ b/config.base.env @@ -7,7 +7,7 @@ GO_VERSION="1.22" HELM_VERSION="3.12.3" IMAGE_PULL_MODE="local" KIND_CLUSTER_NAME="jenkins" -LATEST_LTS_VERSION="2.492.3" +LATEST_LTS_VERSION="2.516.3" NAME="kubernetes-operator" NAMESPACE="default" OPERATOR_SDK_VERSION="1.35.0" diff --git a/pkg/constants/constants.go b/pkg/constants/constants.go index 00e37d7c..ad2faaf0 100644 --- a/pkg/constants/constants.go +++ b/pkg/constants/constants.go @@ -8,7 +8,7 @@ const ( // SeedJobSuffix is a suffix added for all seed jobs SeedJobSuffix = "job-dsl-seed" // DefaultJenkinsMasterImage is the default Jenkins master docker image - DefaultJenkinsMasterImage = "jenkins/jenkins:2.492.3-lts" + DefaultJenkinsMasterImage = "jenkins/jenkins:2.516.3-lts" // DefaultHTTPPortInt32 is the default Jenkins HTTP port DefaultHTTPPortInt32 = int32(8080) // DefaultSlavePortInt32 is the default Jenkins port for slaves diff --git a/pkg/plugins/base_plugins.go b/pkg/plugins/base_plugins.go index ecc42309..9f652b01 100644 --- a/pkg/plugins/base_plugins.go +++ b/pkg/plugins/base_plugins.go @@ -1,14 +1,14 @@ package plugins const ( - configurationAsCodePlugin = "configuration-as-code:1932.v75cb_b_f1b_698d" + configurationAsCodePlugin = "configuration-as-code:1998.v3e50e6e9d9d3" gitPlugin = "git:5.7.0" - jobDslPlugin = "job-dsl:1.89" - kubernetesPlugin = "kubernetes:4295.v7fa_01b_309c95" - kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:1.262.v2670ef7ea_0c5" + jobDslPlugin = "job-dsl:1.93" + kubernetesPlugin = "kubernetes:4384.v1b_6367f393d9" + kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:1.299.v610fa_e76761a_" // Depends on workflow-job which should be automatically downloaded // Hardcoding the workflow-job version leads to frequent breakage - workflowAggregatorPlugin = "workflow-aggregator:600.vb_57cdd26fdd7" + workflowAggregatorPlugin = "workflow-aggregator:608.v67378e9d3db_1" ) // basePluginsList contains plugins to install by operator. diff --git a/test/bats/1-deploy.bats b/test/bats/1-deploy.bats index 2b1cfd80..4cece39b 100644 --- a/test/bats/1-deploy.bats +++ b/test/bats/1-deploy.bats @@ -33,7 +33,7 @@ diag() { --set namespace=${DETIK_CLIENT_NAMESPACE} \ --set operator.image=${OPERATOR_IMAGE} \ --set jenkins.latestPlugins=true \ - --set jenkins.image="jenkins/jenkins:2.492.3-lts" \ + --set jenkins.image="jenkins/jenkins:2.516.3-lts" \ --set jenkins.imagePullPolicy="IfNotPresent" \ --set jenkins.backup.makeBackupBeforePodDeletion=false \ --set jenkins.backup.image=quay.io/jenkins-kubernetes-operator/backup-pvc:e2e-test \ @@ -158,7 +158,7 @@ diag() { --set namespace=${DETIK_CLIENT_NAMESPACE} \ --set operator.image=${OPERATOR_IMAGE} \ --set jenkins.latestPlugins=true \ - --set jenkins.image="jenkins/jenkins:2.492.3-lts" \ + --set jenkins.image="jenkins/jenkins:2.516.3-lts" \ --set jenkins.imagePullPolicy="IfNotPresent" \ --set jenkins.backup.makeBackupBeforePodDeletion=false \ --set jenkins.backup.image=quay.io/jenkins-kubernetes-operator/backup-pvc:e2e-test \ diff --git a/test/bats/2-deploy-with-more-options.bats b/test/bats/2-deploy-with-more-options.bats index 38e00926..aa7b52e8 100644 --- a/test/bats/2-deploy-with-more-options.bats +++ b/test/bats/2-deploy-with-more-options.bats @@ -29,7 +29,7 @@ setup() { --set operator.image=${OPERATOR_IMAGE} \ --set jenkins.latestPlugins=true \ --set jenkins.nodeSelector.batstest=yep \ - --set jenkins.image="jenkins/jenkins:2.492.3-lts" \ + --set jenkins.image="jenkins/jenkins:2.516.3-lts" \ --set jenkins.imagePullPolicy="IfNotPresent" \ --set jenkins.backup.makeBackupBeforePodDeletion=false \ --set jenkins.backup.image=quay.io/jenkins-kubernetes-operator/backup-pvc:e2e-test \ @@ -107,7 +107,7 @@ setup() { --set operator.image=${OPERATOR_IMAGE} \ --set jenkins.latestPlugins=true \ --set jenkins.nodeSelector.batstest=yep \ - --set jenkins.image="jenkins/jenkins:2.492.3-lts" \ + --set jenkins.image="jenkins/jenkins:2.516.3-lts" \ --set jenkins.imagePullPolicy="IfNotPresent" \ --set jenkins.lifecycle.preStop.exec.command="{echo bats-test}" \ --set jenkins.backup.makeBackupBeforePodDeletion=false \ diff --git a/test/bats/3-deploy-with-webhook.bats b/test/bats/3-deploy-with-webhook.bats index 271033d1..e551e79f 100644 --- a/test/bats/3-deploy-with-webhook.bats +++ b/test/bats/3-deploy-with-webhook.bats @@ -29,7 +29,7 @@ setup() { --set namespace=${DETIK_CLIENT_NAMESPACE} \ --set operator.image=${OPERATOR_IMAGE} \ --set jenkins.latestPlugins=true \ - --set jenkins.image="jenkins/jenkins:2.492.3-lts" \ + --set jenkins.image="jenkins/jenkins:2.516.3-lts" \ --set jenkins.imagePullPolicy="IfNotPresent" \ --set jenkins.backup.makeBackupBeforePodDeletion=true \ --set jenkins.backup.image=quay.io/jenkins-kubernetes-operator/backup-pvc:e2e-test \ @@ -90,7 +90,7 @@ setup() { --set namespace=${DETIK_CLIENT_NAMESPACE} \ --set operator.image=${OPERATOR_IMAGE} \ --set jenkins.latestPlugins=true \ - --set jenkins.image="jenkins/jenkins:2.492.3-lts" \ + --set jenkins.image="jenkins/jenkins:2.516.3-lts" \ --set jenkins.imagePullPolicy="IfNotPresent" \ --set jenkins.backup.makeBackupBeforePodDeletion=true \ --set jenkins.backup.image=quay.io/jenkins-kubernetes-operator/backup-pvc:e2e-test \ diff --git a/test/e2e/configuration_test.go b/test/e2e/configuration_test.go index 14fb8b32..93332d75 100644 --- a/test/e2e/configuration_test.go +++ b/test/e2e/configuration_test.go @@ -26,14 +26,14 @@ const e2e = "e2e" // Plugin versions should be the same as in // github.com/jenkinsci/kubernetes-operator/pkg/plugins/base_plugins.go const ( - configurationAsCodePlugin = "configuration-as-code:1932.v75cb_b_f1b_698d" + configurationAsCodePlugin = "configuration-as-code:1998.v3e50e6e9d9d3" gitPlugin = "git:5.7.0" - jobDslPlugin = "job-dsl:1.89" - kubernetesPlugin = "kubernetes:4295.v7fa_01b_309c95" - kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:1.262.v2670ef7ea_0c5" + jobDslPlugin = "job-dsl:1.93" + kubernetesPlugin = "kubernetes:4384.v1b_6367f393d9" + kubernetesCredentialsProviderPlugin = "kubernetes-credentials-provider:1.299.v610fa_e76761a_" // Depends on workflow-job which should be automatically downloaded // Hardcoding the workflow-job version leads to frequent breakage - workflowAggregatorPlugin = "workflow-aggregator:600.vb_57cdd26fdd7" + workflowAggregatorPlugin = "workflow-aggregator:608.v67378e9d3db_1" ) var expectedBasePluginsList = []plugins.Plugin{ diff --git a/test/e2e/test_utility.go b/test/e2e/test_utility.go index 19aadf14..4f131356 100644 --- a/test/e2e/test_utility.go +++ b/test/e2e/test_utility.go @@ -21,7 +21,7 @@ import ( "sigs.k8s.io/controller-runtime/pkg/envtest" ) -const JenkinsTestImage = "jenkins/jenkins:2.492.3-lts" +const JenkinsTestImage = "jenkins/jenkins:2.516.3-lts" var ( Cfg *rest.Config diff --git a/test/helm/helm_test.go b/test/helm/helm_test.go index 97eb81e6..54cccdb8 100644 --- a/test/helm/helm_test.go +++ b/test/helm/helm_test.go @@ -47,7 +47,7 @@ var _ = Describe("Jenkins Controller", func() { cmd := exec.Command("../../bin/helm", "upgrade", "jenkins", "../../chart/jenkins-operator", "--namespace", namespace.Name, "--debug", "--set-string", fmt.Sprintf("jenkins.namespace=%s", namespace.Name), - "--set-string", fmt.Sprintf("jenkins.image=%s", "jenkins/jenkins:2.492.3-lts"), + "--set-string", fmt.Sprintf("jenkins.image=%s", "jenkins/jenkins:2.516.3-lts"), "--set-string", fmt.Sprintf("operator.image=%s", *imageName), "--set-string", fmt.Sprintf("backup.image=%s", "quay.io/jenkins-kubernetes-operator/backup-pvc:e2e-test"), "--set-string", fmt.Sprintf("jenkins.imagePullPolicy=%s", "IfNotPresent"), "--install")