diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d989fa..5dcbf64 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Fixed +- [#170] Fix hanging scripts that create and remove temporary admins + - backport to redmine 5 ## [v5.1.8-4] - 2025-11-27 ### Fixed diff --git a/Dockerfile b/Dockerfile index c46d9bd..1b1bfbc 100644 --- a/Dockerfile +++ b/Dockerfile @@ -143,7 +143,8 @@ RUN set -eux -o pipefail \ && rm -rf /root/* /tmp/* $(gem env gemdir)/cache \ && apk --purge del /.build-deps \ && rm -rf /var/cache/apk/* \ - && apk add ruby-irb + && apk add ruby-irb \ + && chown "${USER}":"${USER}" "${WORKDIR}/Gemfile.lock" WORKDIR ${WORKDIR} diff --git a/Jenkinsfile b/Jenkinsfile index a411915..27c60c1 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1,5 +1,5 @@ #!groovy -@Library(['github.com/cloudogu/ces-build-lib@4.2.0', 'github.com/cloudogu/dogu-build-lib@v3.2.0']) +@Library(['github.com/cloudogu/ces-build-lib@5.1.0', 'github.com/cloudogu/dogu-build-lib@v3.5.1']) import com.cloudogu.ces.cesbuildlib.* import com.cloudogu.ces.dogubuildlib.* @@ -12,6 +12,7 @@ node('vagrant') { Git git = new Git(this, "cesmarvin") git.committerName = 'cesmarvin' git.committerEmail = 'cesmarvin@cloudogu.com' + Makefile makefile = new Makefile(this) GitFlow gitflow = new GitFlow(this, git) GitHub github = new GitHub(this, git) Changelog changelog = new Changelog(this) @@ -139,7 +140,9 @@ node('vagrant') { String releaseVersion = git.getSimpleBranchName(); stage('Finish Release') { - gitflow.finishRelease(releaseVersion) + productionReleaseBranch = makefile.determineGitFlowMainBranch() + developmentBranch = makefile.determineGitFlowDevelopBranch() + gitflow.finishRelease(releaseVersion, productionReleaseBranch, developmentBranch) } stage('Push Dogu to registry') { diff --git a/Makefile b/Makefile index 4de3ecb..913611c 100644 --- a/Makefile +++ b/Makefile @@ -1,4 +1,5 @@ -MAKEFILES_VERSION=9.9.1 +MAKEFILES_VERSION=10.5.0 +BASE_VERSION=5.1.8 .DEFAULT_GOAL:=dogu-release diff --git a/build/make/bats.mk b/build/make/bats.mk index 7e73553..2368044 100644 --- a/build/make/bats.mk +++ b/build/make/bats.mk @@ -9,7 +9,7 @@ BATS_SUPPORT=$(BATS_LIBRARY_DIR)/bats-support BATS_FILE=$(BATS_LIBRARY_DIR)/bats-file BATS_BASE_IMAGE?=bats/bats BATS_CUSTOM_IMAGE?=cloudogu/bats -BATS_TAG?=1.11.0 +BATS_TAG?=1.12.0 BATS_DIR=build/make/bats BATS_WORKDIR="${WORKDIR}"/"${BATS_DIR}" @@ -18,15 +18,19 @@ unit-test-shell: unit-test-shell-$(ENVIRONMENT) $(BATS_ASSERT): @git clone --depth 1 https://github.com/bats-core/bats-assert $@ + @rm -rf $@/.git $(BATS_MOCK): @git clone --depth 1 https://github.com/grayhemp/bats-mock $@ + @rm -rf $@/.git $(BATS_SUPPORT): @git clone --depth 1 https://github.com/bats-core/bats-support $@ + @rm -rf $@/.git $(BATS_FILE): @git clone --depth 1 https://github.com/bats-core/bats-file $@ + @rm -rf $@/.git $(BASH_SRC): BASH_SRC:=$(shell find "${WORKDIR}" -type f -name "*.sh") @@ -49,10 +53,10 @@ unit-test-shell-local: $(BASH_SRC) $(PASSWD) $(ETCGROUP) $(HOME_DIR) buildTestIm "${BATS_DIR}"/customBatsEntrypoint.sh make unit-test-shell-generic-no-junit unit-test-shell-generic: - @bats --formatter junit --output ${BASH_TEST_REPORT_DIR} ${TESTS_DIR} + @bats --report-formatter junit --formatter junit --output ${BASH_TEST_REPORT_DIR} ${TESTS_DIR} unit-test-shell-generic-no-junit: - @bats ${TESTS_DIR} + @bats --report-formatter junit --output ${BASH_TEST_REPORT_DIR} ${TESTS_DIR} .PHONY buildTestImage: buildTestImage: diff --git a/build/make/bats/Dockerfile b/build/make/bats/Dockerfile index 7167a94..95a2787 100644 --- a/build/make/bats/Dockerfile +++ b/build/make/bats/Dockerfile @@ -1,7 +1,7 @@ ARG BATS_BASE_IMAGE ARG BATS_TAG -FROM ${BATS_BASE_IMAGE:-bats/bats}:${BATS_TAG:-1.11.0} +FROM ${BATS_BASE_IMAGE:-bats/bats}:${BATS_TAG:-1.12.0} # Make bash more findable by scripts and tests RUN apk add make git bash diff --git a/build/make/bats/customBatsEntrypoint.sh b/build/make/bats/customBatsEntrypoint.sh index 58856fe..bfc192b 100755 --- a/build/make/bats/customBatsEntrypoint.sh +++ b/build/make/bats/customBatsEntrypoint.sh @@ -3,4 +3,11 @@ set -o errexit set -o nounset set -o pipefail -"$@" \ No newline at end of file +targetReportDir="${PWD}"/target/shell_test_reports +uidgid=1000:1000 +exitcode=0 +"$@" || exitcode=$? +echo "Resetting file ownership to ${uidgid} in ${targetReportDir}/" +chown -R ${uidgid} "${targetReportDir}"/* +echo "exiting with code ${exitcode}" +exit ${exitcode} \ No newline at end of file diff --git a/build/make/build.mk b/build/make/build.mk index a29f2c5..c2f512c 100644 --- a/build/make/build.mk +++ b/build/make/build.mk @@ -3,7 +3,7 @@ ADDITIONAL_LDFLAGS?=-extldflags -static LDFLAGS?=-ldflags "$(ADDITIONAL_LDFLAGS) -X main.Version=$(VERSION) -X main.CommitID=$(COMMIT_ID)" GOIMAGE?=golang -GOTAG?=1.24 +GOTAG?=1.25 GOOS?=linux GOARCH?=amd64 PRE_COMPILE?= diff --git a/build/make/k8s-component.mk b/build/make/k8s-component.mk index 6c1f6c4..4efe639 100644 --- a/build/make/k8s-component.mk +++ b/build/make/k8s-component.mk @@ -1,4 +1,5 @@ -COMPONENT_DEV_VERSION?=${VERSION}-dev +COMPONENT_BUILD_VERSION := $(shell date +%s) +COMPONENT_DEV_VERSION?=${VERSION}-dev.${COMPONENT_BUILD_VERSION} include ${BUILD_DIR}/make/k8s.mk @@ -15,8 +16,9 @@ HELM_RELEASE_TGZ=${HELM_TARGET_DIR}/${ARTIFACT_ID}-${VERSION}.tgz HELM_DEV_RELEASE_TGZ=${HELM_TARGET_DIR}/${ARTIFACT_ID}-${COMPONENT_DEV_VERSION}.tgz HELM_ARTIFACT_NAMESPACE?=k8s ifeq (${RUNTIME_ENV}, remote) - HELM_ARTIFACT_NAMESPACE?=testing/k8s + HELM_ARTIFACT_NAMESPACE=testing/k8s endif +$(info HELM_ARTIFACT_NAMESPACE=$(HELM_ARTIFACT_NAMESPACE)) K8S_RESOURCE_COMPONENT ?= "${K8S_RESOURCE_TEMP_FOLDER}/component-${ARTIFACT_ID}-${VERSION}.yaml" K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML ?= $(BUILD_DIR)/make/k8s-component.tpl @@ -93,10 +95,10 @@ helm-reinstall: helm-delete helm-apply ## Uninstalls the current helm chart and .PHONY: helm-chart-import helm-chart-import: ${CHECK_VAR_TARGETS} helm-generate helm-package ${IMAGE_IMPORT_TARGET} ## Imports the currently available chart into the cluster-local registry. @if [[ ${STAGE} == "development" ]]; then \ - echo "Import ${HELM_DEV_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + echo "Import ${HELM_DEV_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE}..."; \ ${BINARY_HELM} push ${HELM_DEV_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ else \ - echo "Import ${HELM_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + echo "Import ${HELM_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE}..."; \ ${BINARY_HELM} push ${HELM_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ fi @echo "Done." @@ -142,7 +144,7 @@ ${K8S_RESOURCE_COMPONENT_CR_TEMPLATE_YAML}: ${K8S_RESOURCE_TEMP_FOLDER} fi .PHONY: component-apply -component-apply: check-k8s-namespace-env-var ${COMPONENT_PRE_APPLY_TARGETS} ${IMAGE_IMPORT_TARGET} helm-generate helm-chart-import component-generate ## Applies the component yaml resource to the actual defined context. +component-apply: isProduction check-k8s-namespace-env-var ${COMPONENT_PRE_APPLY_TARGETS} ${IMAGE_IMPORT_TARGET} helm-generate helm-chart-import component-generate ## Applies the component yaml resource to the actual defined context. @kubectl apply -f "${K8S_RESOURCE_COMPONENT}" --namespace="${NAMESPACE}" --context="${KUBE_CONTEXT_NAME}" @echo "Done." diff --git a/build/make/k8s-crd.mk b/build/make/k8s-crd.mk index a16292d..aca625d 100644 --- a/build/make/k8s-crd.mk +++ b/build/make/k8s-crd.mk @@ -5,7 +5,8 @@ ifeq ($(APPEND_CRD_SUFFIX), true) else ifeq ($(APPEND_CRD_SUFFIX), false) ARTIFACT_CRD_ID = $(ARTIFACT_ID) endif -DEV_CRD_VERSION ?= ${VERSION}-dev +CRD_BUILD_VERSION := $(shell date +%s).$(TIMESTAMP) +DEV_CRD_VERSION ?= ${VERSION}-dev.${COMPONENT_BUILD_VERSION} HELM_CRD_SOURCE_DIR ?= ${WORKDIR}/k8s/helm-crd HELM_CRD_TARGET_DIR ?= $(K8S_RESOURCE_TEMP_FOLDER)/helm-crd HELM_CRD_RELEASE_TGZ = ${HELM_CRD_TARGET_DIR}/${ARTIFACT_CRD_ID}-${VERSION}.tgz @@ -89,10 +90,10 @@ ${HELM_CRD_RELEASE_TGZ}: ${BINARY_HELM} crd-helm-generate ## Generates and packa .PHONY: crd-helm-chart-import crd-helm-chart-import: ${CHECK_VAR_TARGETS} check-k8s-artifact-id crd-helm-generate crd-helm-package ## Imports the currently available Helm CRD chart into the cluster-local registry. @if [[ ${STAGE} == "development" ]]; then \ - echo "Import ${HELM_CRD_DEV_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + echo "Import ${HELM_CRD_DEV_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE}..."; \ ${BINARY_HELM} push ${HELM_CRD_DEV_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ else \ - echo "Import ${HELM_CRD_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}..."; \ + echo "Import ${HELM_CRD_RELEASE_TGZ} into K8s cluster ${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE}..."; \ ${BINARY_HELM} push ${HELM_CRD_RELEASE_TGZ} oci://${CES_REGISTRY_HOST}/${HELM_ARTIFACT_NAMESPACE} ${BINARY_HELM_ADDITIONAL_PUSH_ARGS}; \ fi @echo "Done." @@ -111,7 +112,7 @@ crd-component-generate: ${K8S_RESOURCE_TEMP_FOLDER} ## Generate the CRD componen fi .PHONY: crd-component-apply -crd-component-apply: check-k8s-namespace-env-var crd-helm-chart-import crd-component-generate ## Applies the CRD component YAML resource to the actual defined context. +crd-component-apply: isProduction check-k8s-namespace-env-var crd-helm-chart-import crd-component-generate ## Applies the CRD component YAML resource to the actual defined context. @kubectl apply -f "${K8S_RESOURCE_CRD_COMPONENT}" --namespace="${NAMESPACE}" --context="${KUBE_CONTEXT_NAME}" @echo "Done." diff --git a/build/make/k8s.mk b/build/make/k8s.mk index d55141c..162abb6 100644 --- a/build/make/k8s.mk +++ b/build/make/k8s.mk @@ -11,7 +11,7 @@ BINARY_YQ_4_VERSION?=v4.40.3 BINARY_HELM = $(UTILITY_BIN_PATH)/helm BINARY_HELM_VERSION?=v3.13.0 CONTROLLER_GEN = $(UTILITY_BIN_PATH)/controller-gen -CONTROLLER_GEN_VERSION?=v0.14.0 +CONTROLLER_GEN_VERSION?=v0.19.0 # Setting SHELL to bash allows bash commands to be executed by recipes. # Options are set to exit when a recipe line exits non-zero or a piped command fails. @@ -203,3 +203,14 @@ envtest: ${ENVTEST} ## Download envtest-setup locally if necessary. ${ENVTEST}: $(call go-get-tool,$(ENVTEST),sigs.k8s.io/controller-runtime/tools/setup-envtest@latest) + +.PHONY: isProduction +isProduction: + @if [[ "${STAGE}" == "production" ]]; then \ + echo "Command executed in production stage. Aborting."; \ + exit 1; \ + else \ + echo "Command executed in development stage. Continuing."; \ + fi + + diff --git a/build/make/release.sh b/build/make/release.sh index 6d6388e..ee70624 100755 --- a/build/make/release.sh +++ b/build/make/release.sh @@ -45,13 +45,15 @@ else CURRENT_TOOL_VERSION=$(get_current_version_by_makefile) fi +BASE_VERSION=$(get_base_version_by_makefile) + NEW_RELEASE_VERSION="$(read_new_version)" validate_new_version "${NEW_RELEASE_VERSION}" if [[ -n "${DRY_RUN}" ]]; then start_dry_run_release "${NEW_RELEASE_VERSION}" else - start_git_flow_release "${NEW_RELEASE_VERSION}" + start_git_flow_release "${NEW_RELEASE_VERSION}" "${BASE_VERSION}" fi update_versions "${NEW_RELEASE_VERSION}" @@ -60,9 +62,9 @@ update_releasenotes "${NEW_RELEASE_VERSION}" show_diff if [[ -n "${DRY_RUN}" ]]; then - abort_dry_run_release "${NEW_RELEASE_VERSION}" + abort_dry_run_release "${NEW_RELEASE_VERSION}" "${BASE_VERSION}" else - finish_release_and_push "${CURRENT_TOOL_VERSION}" "${NEW_RELEASE_VERSION}" + finish_release_and_push "${CURRENT_TOOL_VERSION}" "${NEW_RELEASE_VERSION}" "${BASE_VERSION}" fi echo "=====Finished Release process=====" diff --git a/build/make/release_functions.sh b/build/make/release_functions.sh index f3e1636..0abe86e 100755 --- a/build/make/release_functions.sh +++ b/build/make/release_functions.sh @@ -25,6 +25,11 @@ get_current_version_by_makefile() { grep '^VERSION=[0-9[:alpha:].-]*$' Makefile | sed s/VERSION=//g } +get_base_version_by_makefile() { + BASE_VERSION=$(grep '^BASE_VERSION=[0-9[:alpha:].-]*$' Makefile | sed s/BASE_VERSION=//g) + echo "${BASE_VERSION}" +} + get_current_version_by_dogu_json() { jq ".Version" --raw-output dogu.json } @@ -52,24 +57,47 @@ validate_new_version() { start_git_flow_release() { local NEW_RELEASE_VERSION="${1}" + local BASE_RELEASE_VERSION="${2}" + local BASE_DEV_BRANCH_NAME + # Do gitflow git flow init --defaults --force local mainBranchExists mainBranchExists="$(git show-ref refs/remotes/origin/main || echo "")" - if [ -n "$mainBranchExists" ]; then - echo 'Using "main" branch for production releases' - git flow config set master main - git checkout main - git pull origin main + if [[ -z "$BASE_RELEASE_VERSION" ]]; then + echo "BASE_RELEASE_VERSION variable is empty" + if [ -n "$mainBranchExists" ]; then + echo 'Using "main" branch for production releases' + git flow config set master main + git checkout main + git pull origin main + else + echo 'Using "master" branch for production releases' + git checkout master + git pull origin master + fi + BASE_DEV_BRANCH_NAME="develop" else - echo 'Using "master" branch for production releases' - git checkout master - git pull origin master + echo "BASE_RELEASE_VERSION variable is not empty" + if [[ ${NEW_RELEASE_VERSION} != ${BASE_RELEASE_VERSION}* ]]; then + echo "ERROR: Release version (${NEW_RELEASE_VERSION}) does not start with base version (${BASE_RELEASE_VERSION})" + exit 1 + fi + + BASE_MAIN_BRANCH_NAME="${BASE_RELEASE_VERSION}/main" + echo "Using ${BASE_MAIN_BRANCH_NAME} branch for production releases" + git flow config set master ${BASE_MAIN_BRANCH_NAME} + git checkout ${BASE_MAIN_BRANCH_NAME} + git pull origin ${BASE_MAIN_BRANCH_NAME} + BASE_DEV_BRANCH_NAME="${BASE_RELEASE_VERSION}/develop" fi - git checkout develop - git pull origin develop + git flow config set develop ${BASE_DEV_BRANCH_NAME} + + git checkout ${BASE_DEV_BRANCH_NAME} + git pull origin ${BASE_DEV_BRANCH_NAME} + git flow config git flow release start v"${NEW_RELEASE_VERSION}" } @@ -81,8 +109,17 @@ start_dry_run_release() { abort_dry_run_release() { local NEW_RELEASE_VERSION="${1}" + local BASE_RELEASE_VERSION="${2}" + + local BASE_DEV_BRANCH_NAME + + if [[ -z "$BASE_RELEASE_VERSION" ]]; then + BASE_DEV_BRANCH_NAME="develop" + else + BASE_DEV_BRANCH_NAME="${BASE_RELEASE_VERSION}/develop" + fi - git checkout develop + git checkout ${BASE_DEV_BRANCH_NAME} git branch -D dryrun/v"${NEW_RELEASE_VERSION}" } @@ -302,12 +339,22 @@ show_diff() { finish_release_and_push() { local CURRENT_VERSION="${1}" local NEW_RELEASE_VERSION="${2}" + local BASE_RELEASE_VERSION="${3}" # Push changes and delete release branch wait_for_ok "Upgrade from version v${CURRENT_VERSION} to version v${NEW_RELEASE_VERSION} finished. Should the changes be pushed?" git push origin release/v"${NEW_RELEASE_VERSION}" echo "Switching back to develop and deleting branch release/v${NEW_RELEASE_VERSION}..." - git checkout develop + + local BASE_DEV_BRANCH_NAME + + if [[ -z "$BASE_RELEASE_VERSION" ]]; then + BASE_DEV_BRANCH_NAME="develop" + else + BASE_DEV_BRANCH_NAME="${BASE_RELEASE_VERSION}/develop" + fi + + git checkout ${BASE_DEV_BRANCH_NAME} git branch -D release/v"${NEW_RELEASE_VERSION}" } diff --git a/build/make/static-analysis.mk b/build/make/static-analysis.mk index 9cbc39e..262bc0d 100644 --- a/build/make/static-analysis.mk +++ b/build/make/static-analysis.mk @@ -2,14 +2,14 @@ STATIC_ANALYSIS_DIR=$(TARGET_DIR)/static-analysis GOIMAGE?=golang -GOTAG?=1.24 +GOTAG?=1.25 CUSTOM_GO_MOUNT?=-v /tmp:/tmp REVIEW_DOG=$(TMP_DIR)/bin/reviewdog LINT=$(TMP_DIR)/bin/golangci-lint -LINT_VERSION?=v1.64.8 +LINT_VERSION?=v2.5.0 # ignore tests and mocks -LINTFLAGS=--tests=false --exclude-files="^.*_mock.go$$" --exclude-files="^.*/mock.*.go$$" --timeout 10m --issues-exit-code 0 +LINTFLAGS=--tests=false --timeout 10m --issues-exit-code 0 ADDITIONAL_LINTER=-E bodyclose -E containedctx -E contextcheck -E decorder -E dupl -E errname -E forcetypeassert -E funlen -E unparam .PHONY: static-analysis @@ -47,7 +47,7 @@ $(STATIC_ANALYSIS_DIR)/static-analysis.log: $(STATIC_ANALYSIS_DIR) $(STATIC_ANALYSIS_DIR)/static-analysis-cs.log: $(STATIC_ANALYSIS_DIR) @echo "run static analysis with export to checkstyle format" - @$(LINT) $(LINTFLAGS) run --out-format=checkstyle ./... $(ADDITIONAL_LINTER) > $@ + @$(LINT) $(LINTFLAGS) --output.checkstyle.path stdout run ./... $(ADDITIONAL_LINTER) > $@ $(STATIC_ANALYSIS_DIR): $(LINT) @mkdir -p $(STATIC_ANALYSIS_DIR) diff --git a/build/make/test-unit.mk b/build/make/test-unit.mk index 54a9448..c6994a4 100644 --- a/build/make/test-unit.mk +++ b/build/make/test-unit.mk @@ -9,9 +9,15 @@ COVERAGE_REPORT=$(UNIT_TEST_DIR)/coverage.out PRE_UNITTESTS?= POST_UNITTESTS?= +ASJSON?= + .PHONY: unit-test unit-test: $(XUNIT_JSON) ## Start unit tests +ifeq ($(ENVIRONMENT),ci) +ASJSON='-json' +endif + $(XUNIT_JSON): $(SRC) $(GO_JUNIT_REPORT) ifneq ($(strip $(PRE_UNITTESTS)),) @make $(PRE_UNITTESTS) @@ -21,7 +27,7 @@ endif @echo 'mode: set' > ${COVERAGE_REPORT} @rm -f $(UNIT_TEST_LOG) || true @for PKG in $(PACKAGES) ; do \ - ${GO_CALL} test -v $$PKG -coverprofile=${COVERAGE_REPORT}.tmp -json 2>&1 | tee $(UNIT_TEST_LOG).tmp ; \ + ${GO_CALL} test -v $$PKG -coverprofile=${COVERAGE_REPORT}.tmp ${ASJSON} 2>&1 | tee $(UNIT_TEST_LOG).tmp ; \ cat ${COVERAGE_REPORT}.tmp | tail +2 >> ${COVERAGE_REPORT} ; \ rm -f ${COVERAGE_REPORT}.tmp ; \ cat $(UNIT_TEST_LOG).tmp >> $(UNIT_TEST_LOG) ; \ diff --git a/docs/gui/release_notes_de.md b/docs/gui/release_notes_de.md index 3428d25..0262f3b 100644 --- a/docs/gui/release_notes_de.md +++ b/docs/gui/release_notes_de.md @@ -5,6 +5,9 @@ Im Folgenden finden Sie die Release Notes für das Redmine-Dogu. Technische Details zu einem Release finden Sie im zugehörigen [Changelog](https://docs.cloudogu.com/de/docs/dogus/redmine/CHANGELOG/). ## [Unreleased] +### Fixed +* Die Skripte, die beim Systemstart temporäre Administratoren erstellen und entfernen, werden manchmal nicht beendet. + Dieser Fehler wurde in dieser Version behoben. ## [v5.1.8-4] - 2025-11-27 ### Fixed diff --git a/docs/gui/release_notes_en.md b/docs/gui/release_notes_en.md index 3081fd2..4590e73 100644 --- a/docs/gui/release_notes_en.md +++ b/docs/gui/release_notes_en.md @@ -5,6 +5,9 @@ Below you will find the release notes for the Redmine Dogu. Technical details on a release can be found in the corresponding [Changelog](https://docs.cloudogu.com/en/docs/dogus/redmine/CHANGELOG/). ## [Unreleased] +### Fixed +* The scripts that create and remove temporary admins during startup sometimes don't exit. + This bug was fixed in this version. ## [v5.1.8-4] - 2025-11-27 ### Fixed diff --git a/dogu.json b/dogu.json index 13bc5f1..9939c4a 100644 --- a/dogu.json +++ b/dogu.json @@ -105,6 +105,12 @@ "Name": "rack/bytesize_limit", "Description": "Configure the maximum byte size of query strings that the redmine web server (rack) allows. The default is 4194304 (4 MiB). Depending on the available processing power setting this parameter to high might cause redmine to soft lock.", "Optional": true + }, + { + "Name": "rails_script_timeout", + "Description": "Define after how many seconds the execution of critical rails scripts in the startup process is terminated and tried again", + "Optional": true, + "Default": "180" } ], "Volumes": [ diff --git a/resources/util.sh b/resources/util.sh index cdd6808..7dece90 100644 --- a/resources/util.sh +++ b/resources/util.sh @@ -178,11 +178,12 @@ function create_temporary_admin() { local TMP_ADMIN_RANDOMIZED_STR TMP_ADMIN_RANDOMIZED_STR="$(doguctl random -l 60)" TMP_ADMIN_PASSWORD="${TMP_ADMIN_RANDOMIZED_STR}${TMP_ADMIN_PASSWORD_SUFFIX}" + RAILS_TIMEOUT="$(doguctl config rails_script_timeout)" # In case we are in restart loop to prevent infinite admin users... remove_last_temporary_admin - railsConsole "/rails_scripts/create_admin.rb" --username "${TMP_ADMIN_NAME}" --password "${TMP_ADMIN_PASSWORD}" || exit 1 + railsConsoleRetryOnce "${RAILS_TIMEOUT}" "/rails_scripts/create_admin.rb" --username "${TMP_ADMIN_NAME}" --password "${TMP_ADMIN_PASSWORD}" || exit 1 doguctl config -e "last_tmp_admin" "${TMP_ADMIN_NAME}" } @@ -194,12 +195,13 @@ function remove_last_temporary_admin() { local DEFAULT="" local LAST_TMP_ADMIN LAST_TMP_ADMIN="$(doguctl config -e --default "${DEFAULT}" last_tmp_admin)" + RAILS_TIMEOUT="$(doguctl config rails_script_timeout)" if [ "${LAST_TMP_ADMIN}" != "${DEFAULT}" ] then echo "Removing last temporary admin..." # shellcheck disable=SC1091 - railsConsole "/rails_scripts/remove_user.rb" --username "${LAST_TMP_ADMIN}" || exit 1 + railsConsoleRetryOnce "${RAILS_TIMEOUT}" "/rails_scripts/remove_user.rb" --username "${LAST_TMP_ADMIN}" || exit 1 doguctl config --rm last_tmp_admin fi } @@ -272,6 +274,32 @@ function railsConsole() { rails r -e production "$@" } +function railsConsoleRetryOnce() { + local RETRY_AFTER=${1} + local SCRIPT_NAME=${2} + local SCRIPT_ARGS=("${@:3}") + + echo "Run rails script ${SCRIPT_NAME}" + rails r -e production "${SCRIPT_NAME}" "${SCRIPT_ARGS[@]}" & + + echo "Waiting up to ${RETRY_AFTER} seconds for script ${SCRIPT_NAME} to finish." + local PID=$! + for _ in $(seq 1 "${RETRY_AFTER}"); do + if [[ -d /proc/${PID} ]]; then + sleep 1 + else + # returns exit code of the background process + wait $PID + return $? + fi + done + + echo "Script ${SCRIPT_NAME} did not finish after ${RETRY_AFTER} seconds. Killing it and running it again..." + kill -9 ${PID} + rails r -e production "${SCRIPT_NAME}" "${SCRIPT_ARGS[@]}" + return $? +} + # make the script only run when executed, not when sourced if [[ "${BASH_SOURCE[0]}" == "${0}" ]]; then fetchDatabaseConnection