From ee97cf8ec920dfe4530e9a1d90ac3315341dd9de Mon Sep 17 00:00:00 2001 From: Werner Van Geit Date: Tue, 14 Oct 2025 18:53:34 +0200 Subject: [PATCH 1/2] Switch from docker-compose to docker compose, remove travis --- Makefile | 6 +-- ci/travis/build/devpi | 50 ------------------ ci/travis/build/rabbit-mq | 50 ------------------ ci/travis/docs/workflow.PNG | Bin 41804 -> 0 bytes ci/travis/helpers/check_changes.sh | 26 --------- ci/travis/helpers/install_docker_compose | 9 ---- ci/travis/helpers/show_system_versions | 19 ------- ci/travis/release/devpi | 47 ---------------- ci/travis/tests/devpi | 45 ---------------- devpi/Makefile | 12 ++--- devpi/docker-compose.yml | 3 +- example-config/Makefile | 12 ++--- example-config/docker-compose.yml | 3 +- pip-kit/README.md | 2 +- qooxdoo-kit/Makefile | 12 ++--- qooxdoo-kit/docker-compose.build.yml | 4 +- .../services/client/Makefile | 10 ++-- 17 files changed, 30 insertions(+), 280 deletions(-) delete mode 100755 ci/travis/build/devpi delete mode 100644 ci/travis/build/rabbit-mq delete mode 100644 ci/travis/docs/workflow.PNG delete mode 100755 ci/travis/helpers/check_changes.sh delete mode 100644 ci/travis/helpers/install_docker_compose delete mode 100644 ci/travis/helpers/show_system_versions delete mode 100644 ci/travis/release/devpi delete mode 100644 ci/travis/tests/devpi diff --git a/Makefile b/Makefile index eb1c89c..bb323ee 100644 --- a/Makefile +++ b/Makefile @@ -29,16 +29,16 @@ help: ## This colourful help @awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-.]+:.*?## / {printf "\033[36m%-20s\033[0m %s\n", $$1, $$2}' $(MAKEFILE_LIST) .docker-compose-build.yml: $(docker_compose_configs) - docker-compose $(foreach dc,$^,-f $(dc)) config >$@ + docker compose $(foreach dc,$^,-f $(dc)) config >$@ .PHONY: build build: .docker-compose-build.yml ## Builds all images (uses cache) # building $$(PROJECTS) - docker-compose -f $< build --parallel + docker compose -f $< build --parallel .PHONY: build-nc build-nc: .docker-compose-build.yml ## Builds all images from scratch - docker-compose -f $< build --parallel --no-cache + docker compose -f $< build --parallel --no-cache .PHONY: devenv devenv: .venv ## Nuilds python environment and installs some tooling for operations diff --git a/ci/travis/build/devpi b/ci/travis/build/devpi deleted file mode 100755 index b50fd83..0000000 --- a/ci/travis/build/devpi +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail -IFS=$'\n\t' - -before_install() { - bash ci/travis/helpers/install_docker_compose; - bash ci/travis/helpers/show_system_versions; - env - bash ci/travis/helpers/check_changes.sh devpi/; -} - -install() { - echo "nothing to install..." -} - -before_script() { - echo "nothing to do..." -} - -script() { - pushd devpi; make build; popd -} - -after_success() { - echo "build succeeded" - pushd devpi; make info-image; popd -} - -after_failure() { - echo "build failed" - env - docker images -} - -deploy() { - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; - pushd devpi; make release; popd -} - -# Check if the function exists (bash specific) -if declare -f "$1" > /dev/null -then - # call arguments verbatim - "$@" -else - # Show a helpful error - echo "'$1' is not a known function name" >&2 - exit 1 -fi diff --git a/ci/travis/build/rabbit-mq b/ci/travis/build/rabbit-mq deleted file mode 100644 index 66e73f1..0000000 --- a/ci/travis/build/rabbit-mq +++ /dev/null @@ -1,50 +0,0 @@ -#!/bin/bash -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail -IFS=$'\n\t' - -before_install() { - bash ci/travis/helpers/install_docker_compose; - bash ci/travis/helpers/show_system_versions; - env - bash ci/travis/helpers/check_changes.sh rabbitmq/; -} - -install() { - echo "nothing to install..." -} - -before_script() { - echo "nothing to do..." -} - -script() { - make -C rabbitmq build -} - -after_success() { - echo "build succeeded" - make -C rabbitmq info -} - -after_failure() { - echo "build failed" - env - docker images -} - -deploy() { - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; - pushd rabbitmq; make push; popd -} - -# Check if the function exists (bash specific) -if declare -f "$1" > /dev/null -then - # call arguments verbatim - "$@" -else - # Show a helpful error - echo "'$1' is not a known function name" >&2 - exit 1 -fi diff --git a/ci/travis/docs/workflow.PNG b/ci/travis/docs/workflow.PNG deleted file mode 100644 index 121068153ec23f40ca6ed472d84b4862c4f3043f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 41804 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 C*>qI^ diff --git a/ci/travis/helpers/check_changes.sh b/ci/travis/helpers/check_changes.sh deleted file mode 100755 index 2507cf2..0000000 --- a/ci/travis/helpers/check_changes.sh +++ /dev/null @@ -1,26 +0,0 @@ -#!/bin/bash -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail -IFS=$'\n\t' - -# -# As this repo follows the Monorepo pattern, we want to avoid that Travis make a build for every projects each time one project is updated -# This script checks if one project has been updated. Thanks to https://travis-ci.community/t/how-to-skip-jobs-based-on-the-files-changed-in-a-subdirectory/2979/11 -# - -PATH_TO_SEARCH="$1" - -# 3. Get the latest commit -LATEST_COMMIT=$(git rev-parse HEAD) - -# 4. Get the latest commit in the searched path -LATEST_COMMIT_IN_PATH=$(git log -1 --format=format:%H --full-diff $PATH_TO_SEARCH) - -if [ $LATEST_COMMIT != $LATEST_COMMIT_IN_PATH ]; then - echo "Exiting this job because code in the following path have not changed:" - echo $PATH_TO_SEARCH - exit 1 -fi - -echo "Paths have changed, the build will be deployed" -exit 0 \ No newline at end of file diff --git a/ci/travis/helpers/install_docker_compose b/ci/travis/helpers/install_docker_compose deleted file mode 100644 index 0a31d48..0000000 --- a/ci/travis/helpers/install_docker_compose +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail -IFS=$'\n\t' - -sudo rm /usr/local/bin/docker-compose -curl -L https://github.com/docker/compose/releases/download/${DOCKER_COMPOSE_VERSION}/docker-compose-`uname -s`-`uname -m` > docker-compose -chmod +x docker-compose -sudo mv docker-compose /usr/local/bin diff --git a/ci/travis/helpers/show_system_versions b/ci/travis/helpers/show_system_versions deleted file mode 100644 index 2a581fa..0000000 --- a/ci/travis/helpers/show_system_versions +++ /dev/null @@ -1,19 +0,0 @@ -#!/bin/bash -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail -IFS=$'\n\t' - -uname -a -lsb_release -a - -if command -v python; then - python --version -fi - -if command -v docker; then - docker -v -fi - -if command -v docker-compose; then - docker-compose version -fi diff --git a/ci/travis/release/devpi b/ci/travis/release/devpi deleted file mode 100644 index 56dd72d..0000000 --- a/ci/travis/release/devpi +++ /dev/null @@ -1,47 +0,0 @@ -#!/bin/bash -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail -IFS=$'\n\t' - -before_install() { - bash ci/travis/helpers/install_docker_compose; - bash ci/travis/helpers/show_system_versions; - bash ci/travis/helpers/check_changes.sh devpi/; - env -} - -install() { - echo "nothing to install..." -} - -before_script() { - echo "nothing to do..." -} - -script() { - echo "$DOCKER_PASSWORD" | docker login -u "$DOCKER_USERNAME" --password-stdin; - pushd devpi; make release; popd -} - -after_success() { - echo "Release succeeded" - pushd devpi; make info-image; popd -} - -after_failure() { - echo "Release failed" - env - docker images -} - - -# Check if the function exists (bash specific) -if declare -f "$1" > /dev/null -then - # call arguments verbatim - "$@" -else - # Show a helpful error - echo "'$1' is not a known function name" >&2 - exit 1 -fi diff --git a/ci/travis/tests/devpi b/ci/travis/tests/devpi deleted file mode 100644 index 5234ae5..0000000 --- a/ci/travis/tests/devpi +++ /dev/null @@ -1,45 +0,0 @@ -#!/bin/bash -# http://redsymbol.net/articles/unofficial-bash-strict-mode/ -set -euo pipefail -IFS=$'\n\t' - -before_install() { - bash ci/travis/helpers/install_docker_compose; - bash ci/travis/helpers/show_system_versions; - bash ci/travis/helpers/check_changes.sh devpi/; - env -} - -install() { - echo "nothing to install..." -} - -before_script() { - echo "nothing to do..." -} - -script() { - pushd devpi; make test; popd -} - -after_success() { - echo "Test succeeded" - pushd devpi; make info-image; popd -} - -after_failure() { - echo "Test failed" - env - docker images -} - -# Check if the function exists (bash specific) -if declare -f "$1" > /dev/null -then - # call arguments verbatim - "$@" -else - # Show a helpful error - echo "'$1' is not a known function name" >&2 - exit 1 -fi diff --git a/devpi/Makefile b/devpi/Makefile index 3af90de..330ee5c 100644 --- a/devpi/Makefile +++ b/devpi/Makefile @@ -36,10 +36,10 @@ help: ## This help. .PHONY: build build-nc build: ## Build the container - docker-compose build $(APP_NAME) + docker compose build $(APP_NAME) build-nc: ## Build the container without caching - docker-compose build --no-cache $(APP_NAME) + docker compose build --no-cache $(APP_NAME) .PHONY: test test: .check_version ## Run the tests @@ -47,10 +47,10 @@ test: .check_version ## Run the tests .PHONY: up down up: ## Launch the container - docker-compose up + docker compose up down: ## Stop the container - docker-compose down + docker compose down # Docker tagging .PHONY: tag @@ -88,8 +88,8 @@ clean: .check_clean ## Cleans unversioned files/foldersm remove all temporary fo @git clean -Xdf # removes all temporary folders @-rm -rf $(wildcard $(TMPPREFIX)*) - # cleans close docker-compose - @-docker-compose down + # cleans close docker compose + @-docker compose down clean-images: .check_clean ## Remove all images concerning the current app $(shell docker rmi -f $$(docker images |grep $(DOCKER_IMAGE_NAME))) diff --git a/devpi/docker-compose.yml b/devpi/docker-compose.yml index ba32cba..71fdc41 100644 --- a/devpi/docker-compose.yml +++ b/devpi/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.7' services: devpi: image: ${DOCKER_REPO}/devpi:${VERSION:-latest} @@ -26,4 +25,4 @@ services: DEVPISERVER_DEVPI_USER_TEMPLATE: uid={username},ou=users,dc=example,dc=com DEVPISERVER_DEVPI_GROUP_SEARCH_BASE: ou=groups,dc=example,dc=com DEVPISERVER_DEVPI_GROUP_FILTER: (&(objectClass=posixGroup)(memberUid={username})) - DEVPISERVER_DEVPI_GROUP_ATTRIBUTE_NAME: uid \ No newline at end of file + DEVPISERVER_DEVPI_GROUP_ATTRIBUTE_NAME: uid diff --git a/example-config/Makefile b/example-config/Makefile index 82f0b56..c389ae0 100644 --- a/example-config/Makefile +++ b/example-config/Makefile @@ -30,10 +30,10 @@ help: ## This help. .PHONY: build build-nc build: ## Build the container - docker-compose build $(APP_NAME) + docker compose build $(APP_NAME) build-nc: ## Build the container without caching - docker-compose build --no-cache $(APP_NAME) + docker compose build --no-cache $(APP_NAME) .PHONY: test test: .check_version ## Run the tests @@ -41,10 +41,10 @@ test: .check_version ## Run the tests .PHONY: up down up: ## Launch the container - docker-compose up + docker compose up down: ## Stop the container - docker-compose down + docker compose down # Docker tagging .PHONY: tag @@ -82,8 +82,8 @@ clean: .check_clean ## Cleans unversioned files/foldersm remove all temporary fo @git clean -Xdf # removes all temporary folders @-rm -rf $(wildcard $(TMPPREFIX)*) - # cleans close docker-compose - @-docker-compose down + # cleans close docker compose + @-docker compose down clean-images: .check_clean ## Remove all images concerning the current app $(shell docker rmi -f $$(docker images |grep $(DOCKER_IMAGE_NAME))) diff --git a/example-config/docker-compose.yml b/example-config/docker-compose.yml index 9a2c7a7..7856523 100644 --- a/example-config/docker-compose.yml +++ b/example-config/docker-compose.yml @@ -1,4 +1,3 @@ -version: '3.7' services: devpi: image: ${DOCKER_REPO}/example-config:${VERSION:-latest} # TODO Change example-config by the name of your project @@ -10,4 +9,4 @@ services: org.label-schema.schema-version: "1.0" org.label-schema.build-date: "${BUILD_DATE}" org.label-schema.vcs-url: "${VCS_URL}" - org.label-schema.vcs-ref: "${VCS_REF}" \ No newline at end of file + org.label-schema.vcs-ref: "${VCS_REF}" diff --git a/pip-kit/README.md b/pip-kit/README.md index cbc81e1..a908afd 100644 --- a/pip-kit/README.md +++ b/pip-kit/README.md @@ -31,7 +31,7 @@ echo pip-tools > requirements.in docker -it -v $(pwd):/home/itis/work itisfoundation/pip-kit pip-compile requirements.in # OR -docker-compose run pip-kit pip-compile requirements.in +docker compose run pip-kit pip-compile requirements.in ``` diff --git a/qooxdoo-kit/Makefile b/qooxdoo-kit/Makefile index 31808e4..81d76a2 100644 --- a/qooxdoo-kit/Makefile +++ b/qooxdoo-kit/Makefile @@ -45,11 +45,11 @@ update-packages: ## updates dependencies and recreates package-lock.json build: package-lock.json ## Build the container export VERSION=lastbuild; \ - docker-compose -f docker-compose.build.yml build $(APP_NAME) + docker compose -f docker-compose.build.yml build $(APP_NAME) build-nc: package-lock.json ## Build the container without caching export VERSION=lastbuild; \ - docker-compose -f docker-compose.build.yml build --no-cache $(APP_NAME) + docker compose -f docker-compose.build.yml build --no-cache $(APP_NAME) # Run the container @@ -61,7 +61,7 @@ shell: ## opens shell in container cp -r tests $(TMPDIR) @export VERSION=lastbuild; \ export PROJECT_DIR=$(TMPDIR);\ - docker-compose run $(APP_NAME) + docker compose run $(APP_NAME) .PHONY: test @@ -70,7 +70,7 @@ test: ## tests cp -r tests $(TMPDIR) @export VERSION=lastbuild; export PROJECT_DIR=$(TMPDIR);\ - docker-compose run $(APP_NAME) /bin/sh ./tests/run.sh + docker compose run $(APP_NAME) /bin/sh ./tests/run.sh # Docker tagging @@ -121,8 +121,8 @@ clean: @git clean -Xdf # removes all temporary folders @-rm -rf $(wildcard $(TMPPREFIX)*) - # cleans close docker-compose - @-docker-compose down + # cleans close docker compose + @-docker compose down .PHONY: clean-images clean-images: diff --git a/qooxdoo-kit/docker-compose.build.yml b/qooxdoo-kit/docker-compose.build.yml index 57b0799..41fc728 100644 --- a/qooxdoo-kit/docker-compose.build.yml +++ b/qooxdoo-kit/docker-compose.build.yml @@ -1,8 +1,6 @@ -version: '3.7' services: qooxdoo-kit: image: ${DOCKER_REPO:-itisfoundation}/qooxdoo-kit:${VERSION:-lastbuild} - # init: true See #11 build: context: . cache_from: @@ -14,4 +12,4 @@ services: org.label-schema.vcs-ref: "${VCS_REF}" swiss.itis.dockerfiles.qooxdoo-kit.qooxdoo-compiler-version : "${QOOXDOO_COMPILER_VERSION}" swiss.itis.dockerfiles.qooxdoo-kit.qooxdoo-framework-version : "${QOOXDOO_FRAMEWORK_VERSION}" - swiss.itis.dockerfiles.qooxdoo-kit.puppeteer-version : "${PUPPETEER_VERSION}" \ No newline at end of file + swiss.itis.dockerfiles.qooxdoo-kit.puppeteer-version : "${PUPPETEER_VERSION}" diff --git a/qooxdoo-kit/samples/simcore-integration (before)/services/client/Makefile b/qooxdoo-kit/samples/simcore-integration (before)/services/client/Makefile index d664a3d..4a1aedd 100644 --- a/qooxdoo-kit/samples/simcore-integration (before)/services/client/Makefile +++ b/qooxdoo-kit/samples/simcore-integration (before)/services/client/Makefile @@ -24,20 +24,20 @@ info: .PHONY: build-devel # target: build-devel: – Builds dev container build-devel: - export BUILD_TARGET=development; docker-compose build + export BUILD_TARGET=development; docker compose build .PHONY: build # target: build: – Builds container build: - export BUILD_TARGET=build; docker-compose build + export BUILD_TARGET=build; docker compose build docker run -it client_qx:build /bin/sh -c "ls -l build-output;cat build-output/version.txt" .PHONY: clean # target: clean: – Cleans images and current dir outputs clean: - @docker-compose down + @docker compose down @docker image rm -f client_qx:build 2> /dev/null @docker image rm -f client_qx:development 2> /dev/null @git clean -dxf ${CURDIR} @@ -47,7 +47,7 @@ clean: # target: compile: – Compiles front-end's code [dev] compile: export BUILD_TARGET=development; \ - docker-compose run --service-ports qx compile \ + docker compose run --service-ports qx compile \ --set osparc.vcsRef='"${VCS_REF}"' \ --set osparc.vcsRefClient='"${VCS_REF_CLIENT}"' \ --set osparc.vcsStatusClient='"${VCS_STATUS_CLIENT}"' \ @@ -58,4 +58,4 @@ compile: # target: serve: – Compiles, watches and serves front-end's code [dev] serve: export BUILD_TARGET=development; \ - docker-compose run --service-ports qx + docker compose run --service-ports qx From eb37f5ebb33383a3dda2e1a07c2234a19b403a0e Mon Sep 17 00:00:00 2001 From: Werner Van Geit Date: Wed, 15 Oct 2025 14:28:47 +0200 Subject: [PATCH 2/2] Add info-tools target in makefile --- Makefile | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/Makefile b/Makefile index bb323ee..d529c64 100644 --- a/Makefile +++ b/Makefile @@ -51,3 +51,17 @@ devenv: .venv ## Nuilds python environment and installs some tooling for operat clean: ## Cleans all unversioned files in project @echo -n "Are you sure? [y/N] " && read ans && [ $${ans:-N} = y ] @git clean -dxf + +.PHONY: info-tools +info-tools: ## displays tools versions + @echo dev-tools versions ------------------------- + @echo ' awk : $(shell awk -W version 2>&1 | head -n 1)' + @echo ' docker : $(shell docker --version)' + @echo ' docker buildx : $(shell docker buildx version)' + @echo ' docker compose: $(shell docker compose version)' + @echo ' jq : $(shell jq --version)' + @echo ' make : $(shell make --version 2>&1 | head -n 1)' + @echo ' node : $(shell node --version 2> /dev/null || echo ERROR nodejs missing)' + @echo ' python : $(shell python3 --version)' + @echo ' uv : $(shell uv --version 2> /dev/null || echo ERROR uv missing)' + @echo ' ubuntu : $(shell lsb_release --description --short 2> /dev/null | tail || echo ERROR Not an Ubuntu OS )'