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 "+ $@"