From 791349910b75e8b9b6989b1c6ca0b41468e66309 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 10:25:08 +0200 Subject: [PATCH 01/14] STAC-25137 Tolerate dict/list/str customHostMetadata in Dynatrace HostEntity Dynatrace returns properties.customHostMetadata inconsistently across environments: as a {key: value} dict in some and as a list of {'key':.., 'value':..} objects in others. HostProperties.customHostMetadata was typed as Dict[str, Any], so the list shape failed Pydantic validation and the whole host entity was silently dropped from topology (observed at Rabobank, ~16 hosts skipped at dynatrace_topology.py:398). Parse the field tolerantly: accept a dict, else a list, else a string, falling back to str() for any other non-null type, so a single type mismatch no longer drops the entity. Mirrors the existing convert_custom_pg_metadata approach for the sibling customPgMetadata field. Adds regression tests for the list (production), dict, string and non-scalar -> str cases. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .../dynatrace_topology/entity_data_types.py | 18 ++- .../tests/test_dynatrace_topology.py | 106 ++++++++++++++++++ 2 files changed, 123 insertions(+), 1 deletion(-) diff --git a/dynatrace_topology/stackstate_checks/dynatrace_topology/entity_data_types.py b/dynatrace_topology/stackstate_checks/dynatrace_topology/entity_data_types.py index 57492c0b..28da08e6 100644 --- a/dynatrace_topology/stackstate_checks/dynatrace_topology/entity_data_types.py +++ b/dynatrace_topology/stackstate_checks/dynatrace_topology/entity_data_types.py @@ -95,7 +95,23 @@ class HostProperties(ForgivingBaseModel): cloudType: Optional[str] = None conditionalName: Optional[str] = None cpuCores: Optional[int] = None - customHostMetadata: Dict[str, Any] = field(default_factory=dict) + customHostMetadata: Union[Dict[str, Any], List[Any], str] = field(default_factory=dict) + + @field_validator('customHostMetadata', mode='before') + @classmethod + def coerce_custom_host_metadata(cls, v): + """Parse customHostMetadata tolerantly: as a dict, else a list, else a string. + + Dynatrace returns this field inconsistently across environments: as a + ``{key: value}`` dict in some, and as a list of ``{'key':.., 'value':..}`` + objects in others. Accept either shape as-is, falling back to a string + representation for any other (non-null) type, so a single type mismatch does + not cause the whole host entity to be dropped from topology (STAC-25137). + """ + if v is None or isinstance(v, (dict, list, str)): + return v + return str(v) + customizedName: Optional[str] = None detectedName: Optional[str] = None dnsNames: List[str] = field(default_factory=list) diff --git a/dynatrace_topology/tests/test_dynatrace_topology.py b/dynatrace_topology/tests/test_dynatrace_topology.py index 80456760..838dcebd 100644 --- a/dynatrace_topology/tests/test_dynatrace_topology.py +++ b/dynatrace_topology/tests/test_dynatrace_topology.py @@ -626,6 +626,112 @@ def test_process_group_entity_custompgmetadata_nonscalar_key(): assert entity.properties.customPgMetadata['cni.projectcalico.org/podIPs'] == '10.7.3.85/32' +def test_host_entity_customhostmetadata_list_handling(): + """ + Test that HostEntity tolerates customHostMetadata as a list of key-value objects. + Reproduces the Rabobank production error (STAC-25137): + "Input should be a valid dictionary [type=dict_type, + input_value=[{'value': 'VM4', 'key': 'ENVIRONMENT'}, ...], input_type=list]" + """ + from stackstate_checks.dynatrace_topology.entity_data_types import HostEntity + + test_data = { + 'entityId': 'HOST-0C4456C4494C5BF5', + 'type': 'HOST', + 'displayName': 'lspe003490.eu.rabonet.com', + 'properties': { + 'customHostMetadata': [ + {'value': 'VM4', 'key': 'ENVIRONMENT'}, + {'value': 'VM', 'key': 'VM'}, + ] + } + } + + # This must no longer raise a validation error; the host must not be dropped. + entity = HostEntity.model_validate(test_data) + + # The list shape is preserved as-is (tolerant parse: dict -> list -> str). + assert isinstance(entity.properties.customHostMetadata, list) + assert entity.properties.customHostMetadata == [ + {'value': 'VM4', 'key': 'ENVIRONMENT'}, + {'value': 'VM', 'key': 'VM'}, + ] + # Downstream serialization (used to build topology) must succeed and keep the shape. + dumped = entity.model_dump(mode="json", exclude_none=True) + assert dumped['properties']['customHostMetadata'] == [ + {'value': 'VM4', 'key': 'ENVIRONMENT'}, + {'value': 'VM', 'key': 'VM'}, + ] + + +def test_host_entity_customhostmetadata_dict_handling(): + """ + Test that HostEntity still accepts customHostMetadata as a dict (original/mock format). + """ + from stackstate_checks.dynatrace_topology.entity_data_types import HostEntity + + test_data = { + 'entityId': 'HOST-0C4456C4494C5BF5', + 'type': 'HOST', + 'displayName': 'lspe003490.eu.rabonet.com', + 'properties': { + 'customHostMetadata': { + 'ENVIRONMENT': 'VM4', + 'VM': 'VM', + } + } + } + + entity = HostEntity.model_validate(test_data) + + assert isinstance(entity.properties.customHostMetadata, dict) + assert entity.properties.customHostMetadata['ENVIRONMENT'] == 'VM4' + assert entity.properties.customHostMetadata['VM'] == 'VM' + + +def test_host_entity_customhostmetadata_string_handling(): + """ + Test that HostEntity tolerates customHostMetadata delivered as a plain string. + """ + from stackstate_checks.dynatrace_topology.entity_data_types import HostEntity + + test_data = { + 'entityId': 'HOST-0C4456C4494C5BF5', + 'type': 'HOST', + 'displayName': 'lspe003490.eu.rabonet.com', + 'properties': { + 'customHostMetadata': 'ENVIRONMENT=VM4' + } + } + + entity = HostEntity.model_validate(test_data) + + assert isinstance(entity.properties.customHostMetadata, str) + assert entity.properties.customHostMetadata == 'ENVIRONMENT=VM4' + + +def test_host_entity_customhostmetadata_other_type_fallback(): + """ + Test that a customHostMetadata value that is neither dict, list nor string falls back + to its string representation instead of dropping the host entity. + """ + from stackstate_checks.dynatrace_topology.entity_data_types import HostEntity + + test_data = { + 'entityId': 'HOST-0C4456C4494C5BF5', + 'type': 'HOST', + 'displayName': 'lspe003490.eu.rabonet.com', + 'properties': { + 'customHostMetadata': 42 + } + } + + entity = HostEntity.model_validate(test_data) + + assert isinstance(entity.properties.customHostMetadata, str) + assert entity.properties.customHostMetadata == '42' + + def test_entity_cache_resets_between_runs(requests_mock, dynatrace_check, topology, aggregator): """ Verify that the in-memory entity cache is cleared at the start of each check run. From 65dfb5060a82144270b6fbb4502a360ed6fd2b4e Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 10:59:28 +0200 Subject: [PATCH 02/14] STAC-25137: document that CI image Python tracks the agent's embedded Python The CI runner image's Python must match the CPython the StackState Agent embeds (omnibus/config/software/python3.rb default_version, mirrored in .python-version). Bumping it is part of the agent upstream-merge process, not ad-hoc work; expanded the 'CI image' README section to point at UPSTREAM_MERGE.md and list the files to change. Keeps integrations CI on the interpreter the agent ships so version-specific bugs (e.g. pydantic validation differences, cf. STAC-25137) are caught before release. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- README.md | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8555c223..3391e858 100644 --- a/README.md +++ b/README.md @@ -79,7 +79,19 @@ You can optionally pass a log level parameter, if not passed logging is disabled ## CI image -The CI image is built from `.setup-scripts/image`. +The CI image is built from `.setup-scripts/image` and published to +`registry.tooling.stackstate.io` (referenced by `image:` in `.gitlab-ci.yml`). + +Its Python **must match the CPython that the StackState Agent embeds** — the +agent's `omnibus/config/software/python3.rb` `default_version`, mirrored here in +`.python-version`. Bumping it is part of the **agent upstream-merge process**, +not ad-hoc work: see the agent repo's `UPSTREAM_MERGE.md`, section "Integrations +repo: CI runner image (embedded Python bump)", for the exact files to change +(`.setup-scripts/image/Dockerfile`, `.setup-scripts/image/Makefile`, +`.setup-scripts/setup_env.sh`, `.gitlab-ci.yml`, `.python-version`) and the +rebuild/publish steps. Keeping them in sync ensures CI tests run on the same +interpreter the agent ships, so version-specific bugs (e.g. pydantic validation +differences) are caught before release rather than in production. ## Dynatrace feeder We also expose a script to feed some fake data into Dynatrace. It reads logs and metrics from inside a provided directory and shoots them to the Dynatrace API to have a reproducible setup. From 8325837240fb4567db4883d6a7cda9896e37e91c Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 12:18:37 +0200 Subject: [PATCH 03/14] STAC-25137 Build new docker image. Bump integrations CI runner to Python 3.13.14 (bookworm base): Dockerfile, Makefile, setup_env.sh, conda_env.ps1, .python-version, and .gitlab-ci.yml (RUNNER_IMAGE_TAG variable, docker job, stackstate-7.78.2 branch rules). Auto-run the docker job when the commit message contains "Build new docker image". Co-authored-by: Cursor --- .gitlab-ci.yml | 42 ++++++++++++++++++++++++++------- .python-version | 2 +- .setup-scripts/conda_env.ps1 | 2 +- .setup-scripts/image/Dockerfile | 13 ++++++---- .setup-scripts/image/Makefile | 18 ++++++++++---- .setup-scripts/setup_env.sh | 4 ++-- README.md | 24 +++++++++++++------ 7 files changed, 78 insertions(+), 27 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 073f19cd..ff97c0b8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -1,4 +1,4 @@ -image: ${REGISTRY_DOCKER_URL}/stackstate/stackstate-agent-integrations-runner:20241120-py311 +image: ${REGISTRY_DOCKER_URL}/stackstate/stackstate-agent-integrations-runner:${RUNNER_IMAGE_TAG} stages: - build - test @@ -6,7 +6,10 @@ stages: variables: CONDA_ENV: "stackstate-agent-integrations-py-3" - PYTHON_VERSION: 3.13.13 + PYTHON_VERSION: 3.13.14 + # py3.13 runner: run the manual `docker` job, then set RUNNER_IMAGE_TAG to the + # YYYYMMDD-py313 tag it prints AND bump setup_env.sh/conda_env.ps1 to python3.13. + RUNNER_IMAGE_TAG: "20241120-py311" .rules: - &pull_requests @@ -24,7 +27,7 @@ variables: - $CHECK/* - $CHECK/**/* - &master_branch - if: '$CI_COMMIT_BRANCH == "stackstate-7.71.2"' + if: '$CI_COMMIT_BRANCH == "stackstate-7.78.2"' - &release_branch if: $CI_COMMIT_TAG - &base_manual_changes @@ -48,7 +51,7 @@ variables: - splunk_base/* - splunk_base/**/* - &master_manual_branch - if: '$CI_COMMIT_BRANCH == "stackstate-7.71.2"' + if: '$CI_COMMIT_BRANCH == "stackstate-7.78.2"' when: manual allow_failure: true - &release_manual_branch @@ -120,18 +123,41 @@ print_env: interruptible: true docker: - <<: *manual_job_rules image: ${REGISTRY_DOCKER_URL}/library/docker:20-git stage: build + rules: + - if: $CI_COMMIT_MESSAGE =~ /Build new docker image/i + when: on_success + - if: $CI_PIPELINE_SOURCE == "merge_request_event" + changes: + - .setup-scripts/image/**/* + - .setup-scripts/setup_env.sh + when: manual + allow_failure: true + - if: $CI_EXTERNAL_PULL_REQUEST_IID + when: manual + allow_failure: true + - if: '$CI_COMMIT_BRANCH == "stackstate-7.78.2"' + when: manual + allow_failure: true + - if: $CI_COMMIT_TAG + when: manual + allow_failure: true script: - echo "${docker_password}" | docker login --username=${docker_user} --password-stdin docker.io - echo "${quay_password}" | docker login --username=${quay_user} --password-stdin quay.io - echo "${REGISTRY_PASSWORD}" | docker login --username=${REGISTRY_USER} --password-stdin ${REGISTRY_HOST} - apk add make - cd .setup-scripts/image - - make build - - make push - - if [ "${CI_COMMIT_REF_NAME}" = "stackstate-7.71.2" ]; then make tag_latest; make push_latest; fi + # Pull base from docker.io during build; mirror may not have 3.13.14-bookworm yet. + - make build push PYTHON_BASE_IMAGE=python:3.13.14-bookworm + - RUNNER_TAG=$(make -s print_tag) + - echo "Published ${REGISTRY_DOCKER_URL}/stackstate/stackstate-agent-integrations-runner:${RUNNER_TAG}" + - echo "Set RUNNER_IMAGE_TAG to ${RUNNER_TAG} (setup_env.sh/conda_env.ps1 already target python3.13/3.13.14), then re-run the pipeline." + - | + if [ "${CI_COMMIT_REF_NAME}" = "stackstate-7.78.2" ]; then + make tag_latest push_latest + fi services: - alias: docker command: diff --git a/.python-version b/.python-version index 655354de..0cf960df 100644 --- a/.python-version +++ b/.python-version @@ -1 +1 @@ -3.13.13 +3.13.14 diff --git a/.setup-scripts/conda_env.ps1 b/.setup-scripts/conda_env.ps1 index 59d3c359..20002eee 100644 --- a/.setup-scripts/conda_env.ps1 +++ b/.setup-scripts/conda_env.ps1 @@ -1,7 +1,7 @@ $envName = $args[0] $pythonVersion = $args[1] if ($pythonVersion -eq '3') { - $pythonVersion = '3.11' + $pythonVersion = '3.13.14' } $env_name = conda env list | grep $envName | awk '{print $1}' if (($env_name -ne $null) -and ($env_name -eq $envName)) { diff --git a/.setup-scripts/image/Dockerfile b/.setup-scripts/image/Dockerfile index f3fcb82d..adabd75f 100644 --- a/.setup-scripts/image/Dockerfile +++ b/.setup-scripts/image/Dockerfile @@ -1,11 +1,16 @@ -FROM registry.tooling.stackstate.io/docker/python:3.11.14-bullseye +# Match agent embedded CPython 3.13.14. Docker Hub publishes 3.13.14 on bookworm, not bullseye. +# CI `docker` job passes PYTHON_BASE_IMAGE=python:3.13.14-bookworm (docker.io is logged in there). +ARG PYTHON_BASE_IMAGE=registry.tooling.stackstate.io/docker/python:3.13.14-bookworm +FROM ${PYTHON_BASE_IMAGE} RUN apt-get update && \ - apt-get install -y virtualenv apt-transport-https ca-certificates curl gnupg2 software-properties-common && \ + apt-get install -y virtualenv apt-transport-https ca-certificates curl gnupg2 lsb-release && \ apt-get clean && \ pip3 install -U pip setuptools codecov wheel -RUN curl -fsSL https://download.docker.com/linux/debian/gpg | apt-key add - -RUN add-apt-repository -y "deb [arch=amd64] https://download.docker.com/linux/debian $(lsb_release -cs) stable" && \ +RUN install -m 0755 -d /etc/apt/keyrings && \ + curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && \ + chmod a+r /etc/apt/keyrings/docker.asc && \ + echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/debian $(. /etc/os-release && echo "$VERSION_CODENAME") stable" | tee /etc/apt/sources.list.d/docker.list > /dev/null && \ apt-get update && \ apt-get install -y docker-ce docker-ce-cli containerd.io && \ apt-get clean diff --git a/.setup-scripts/image/Makefile b/.setup-scripts/image/Makefile index 71572d35..6f48f7f3 100644 --- a/.setup-scripts/image/Makefile +++ b/.setup-scripts/image/Makefile @@ -1,4 +1,8 @@ RUNTIMETAG := $(shell date +%Y%m%d) +PYTHON_SUFFIX := py313 +IMAGE_REPO ?= stackstate/stackstate-agent-integrations-runner +# CI `docker` job overrides with python:3.13.14-bookworm (docker.io login); local default is the mirror. +PYTHON_BASE_IMAGE ?= registry.tooling.stackstate.io/docker/python:3.13.14-bookworm #build: # docker build -t stackstate/stackstate-agent-integrations-runner:$(RUNTIMETAG) . @@ -16,12 +20,18 @@ RUNTIMETAG := $(shell date +%Y%m%d) # vvv New runner build: - docker build -t stackstate/stackstate-agent-integrations-runner:$(RUNTIMETAG)-py311 . + docker build --build-arg PYTHON_BASE_IMAGE=$(PYTHON_BASE_IMAGE) \ + -t $(IMAGE_REPO):$(RUNTIMETAG)-$(PYTHON_SUFFIX) . + push: - docker push stackstate/stackstate-agent-integrations-runner:$(RUNTIMETAG)-py311 + docker push $(IMAGE_REPO):$(RUNTIMETAG)-$(PYTHON_SUFFIX) tag_latest: - docker tag stackstate/stackstate-agent-integrations-runner:$(RUNTIMETAG)-py311 stackstate/stackstate-agent-integrations-runner:latest-py311 + docker tag $(IMAGE_REPO):$(RUNTIMETAG)-$(PYTHON_SUFFIX) $(IMAGE_REPO):latest-$(PYTHON_SUFFIX) push_latest: - docker push stackstate/stackstate-agent-integrations-runner:latest-py311 \ No newline at end of file + docker push $(IMAGE_REPO):latest-$(PYTHON_SUFFIX) + +# Print the tag CI should set as RUNNER_IMAGE_TAG after a successful publish. +print_tag: + @echo $(RUNTIMETAG)-$(PYTHON_SUFFIX) diff --git a/.setup-scripts/setup_env.sh b/.setup-scripts/setup_env.sh index deacc6bd..13539098 100755 --- a/.setup-scripts/setup_env.sh +++ b/.setup-scripts/setup_env.sh @@ -12,7 +12,7 @@ VENV_PATH=$INTEGRATIONS_DIR_TMP/venv if [ ! -d $VENV_PATH ]; then echo "$VENV_PATH doesn't exist, create the venv and loading deps" - virtualenv --python=python3.11 --pip=23.3.1 --setuptools=44.1.1 $INTEGRATIONS_DIR_TMP/venv + virtualenv --python=python3.13 --pip=23.3.1 --setuptools=44.1.1 $INTEGRATIONS_DIR_TMP/venv source $INTEGRATIONS_DIR_TMP/venv/bin/activate pip install pylint==2.17.2 pip install docker==6.1.3 @@ -24,7 +24,7 @@ if [ ! -d $VENV_PATH ]; then else echo "$VENV_PATH already exists, only activating the venv" ls $INTEGRATIONS_DIR_TMP/venv/bin || echo 'no bin' - ls $INTEGRATIONS_DIR_TMP/venv/lib/python3.11/site-packages || echo 'no site-packages' + ls $INTEGRATIONS_DIR_TMP/venv/lib/python3.13/site-packages || echo 'no site-packages' source $INTEGRATIONS_DIR_TMP/venv/bin/activate pip install pylint==2.17.2 pip install docker==6.1.3 diff --git a/README.md b/README.md index 3391e858..765283bc 100644 --- a/README.md +++ b/README.md @@ -80,18 +80,28 @@ You can optionally pass a log level parameter, if not passed logging is disabled ## CI image The CI image is built from `.setup-scripts/image` and published to -`registry.tooling.stackstate.io` (referenced by `image:` in `.gitlab-ci.yml`). +`registry.tooling.stackstate.io` (referenced by `RUNNER_IMAGE_TAG` in +`.gitlab-ci.yml`). **Do not build or push it locally** except for ad-hoc +validation — use the GitLab CI `docker` job (build stage, manual). Its Python **must match the CPython that the StackState Agent embeds** — the agent's `omnibus/config/software/python3.rb` `default_version`, mirrored here in `.python-version`. Bumping it is part of the **agent upstream-merge process**, not ad-hoc work: see the agent repo's `UPSTREAM_MERGE.md`, section "Integrations -repo: CI runner image (embedded Python bump)", for the exact files to change -(`.setup-scripts/image/Dockerfile`, `.setup-scripts/image/Makefile`, -`.setup-scripts/setup_env.sh`, `.gitlab-ci.yml`, `.python-version`) and the -rebuild/publish steps. Keeping them in sync ensures CI tests run on the same -interpreter the agent ships, so version-specific bugs (e.g. pydantic validation -differences) are caught before release rather than in production. +repo: CI runner image (embedded Python bump)". + +After merging Dockerfile / Makefile changes: + +1. Run the manual **`docker`** job on the pipeline (it builds from + `python:3.13.14-bookworm` and pushes `YYYYMMDD-py313` to the registry). +2. In a follow-up commit, set `RUNNER_IMAGE_TAG` in `.gitlab-ci.yml` to the tag + the job prints, and ensure `setup_env.sh` uses `python3.13` and + `conda_env.ps1` defaults to `3.13.14` (must land together with the runner switch). +3. Re-run the pipeline so test jobs use the new runner. + +Keeping runner Python in sync ensures CI tests run on the same interpreter the +agent ships, so version-specific bugs (e.g. pydantic validation differences) are +caught before release rather than in production. ## Dynatrace feeder We also expose a script to feed some fake data into Dynatrace. It reads logs and metrics from inside a provided directory and shoots them to the Dynatrace API to have a reproducible setup. From 3770ad0f5ea1effec86d3e2dc413e79211a2586b Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 12:23:38 +0200 Subject: [PATCH 04/14] STAC-25137 Point CI at py3.13.14 runner image 20260625-py313 Switch RUNNER_IMAGE_TAG after the docker job published registry.tooling.stackstate.io/.../stackstate-agent-integrations-runner:20260625-py313. Co-authored-by: Cursor --- .gitlab-ci.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index ff97c0b8..28989612 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -7,9 +7,7 @@ stages: variables: CONDA_ENV: "stackstate-agent-integrations-py-3" PYTHON_VERSION: 3.13.14 - # py3.13 runner: run the manual `docker` job, then set RUNNER_IMAGE_TAG to the - # YYYYMMDD-py313 tag it prints AND bump setup_env.sh/conda_env.ps1 to python3.13. - RUNNER_IMAGE_TAG: "20241120-py311" + RUNNER_IMAGE_TAG: "20260625-py313" .rules: - &pull_requests From 64ad7a1fbcd0e9be95f311415a8af3b93f125021 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 12:27:11 +0200 Subject: [PATCH 05/14] STAC-25137 Fix linux_deps venv creation on Python 3.13 Debian bookworm's apt virtualenv cannot seed py3.13 with the legacy --pip=23.3.1 --setuptools=44.1.1 pins (job 15030656775). Use stdlib python3.13 -m venv instead. Drop unused apt virtualenv from the runner Dockerfile for the next image rebuild. Co-authored-by: Cursor --- .setup-scripts/image/Dockerfile | 2 +- .setup-scripts/setup_env.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.setup-scripts/image/Dockerfile b/.setup-scripts/image/Dockerfile index adabd75f..71742c04 100644 --- a/.setup-scripts/image/Dockerfile +++ b/.setup-scripts/image/Dockerfile @@ -3,7 +3,7 @@ ARG PYTHON_BASE_IMAGE=registry.tooling.stackstate.io/docker/python:3.13.14-bookworm FROM ${PYTHON_BASE_IMAGE} RUN apt-get update && \ - apt-get install -y virtualenv apt-transport-https ca-certificates curl gnupg2 lsb-release && \ + apt-get install -y apt-transport-https ca-certificates curl gnupg2 lsb-release && \ apt-get clean && \ pip3 install -U pip setuptools codecov wheel diff --git a/.setup-scripts/setup_env.sh b/.setup-scripts/setup_env.sh index 13539098..d84fa39e 100755 --- a/.setup-scripts/setup_env.sh +++ b/.setup-scripts/setup_env.sh @@ -12,7 +12,7 @@ VENV_PATH=$INTEGRATIONS_DIR_TMP/venv if [ ! -d $VENV_PATH ]; then echo "$VENV_PATH doesn't exist, create the venv and loading deps" - virtualenv --python=python3.13 --pip=23.3.1 --setuptools=44.1.1 $INTEGRATIONS_DIR_TMP/venv + python3.13 -m venv $INTEGRATIONS_DIR_TMP/venv source $INTEGRATIONS_DIR_TMP/venv/bin/activate pip install pylint==2.17.2 pip install docker==6.1.3 From 5d8dc1a30d06bfa08d5a848119a230fdc6f850e2 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 12:32:26 +0200 Subject: [PATCH 06/14] STAC-25137 Pin Python 3.13-compatible pip and setuptools Centralize pip 24.3.1 and setuptools 75.8.2 in python_tool_versions.env for CI venv setup, tox, Windows conda, and the runner Dockerfile. Replaces legacy pins that cannot bootstrap Python 3.13. Co-authored-by: Cursor --- .setup-scripts/conda_env.ps1 | 4 ++-- .setup-scripts/image/Dockerfile | 4 +++- .setup-scripts/image/Makefile | 4 ++++ .setup-scripts/python_tool_versions.env | 3 +++ .setup-scripts/setup_env.sh | 6 ++++-- agent_integration_sample/tox.ini | 2 +- agent_v2_integration_sample/tox.ini | 2 +- agent_v2_integration_stateful_sample/tox.ini | 2 +- agent_v2_integration_transactional_sample/tox.ini | 2 +- kubelet/tox.ini | 2 +- openmetrics/tox.ini | 2 +- servicenow/tox.ini | 2 +- splunk_base/tox.ini | 2 +- splunk_health/tox.ini | 2 +- splunk_metric/tox.ini | 2 +- splunk_topology/tox.ini | 2 +- stackstate_checks_dev/tox.ini | 2 +- static_health/tox.ini | 2 +- static_topology/tox.ini | 2 +- vsphere/tox.ini | 2 +- zabbix/tox.ini | 2 +- 21 files changed, 32 insertions(+), 21 deletions(-) create mode 100644 .setup-scripts/python_tool_versions.env diff --git a/.setup-scripts/conda_env.ps1 b/.setup-scripts/conda_env.ps1 index 20002eee..6755a21f 100644 --- a/.setup-scripts/conda_env.ps1 +++ b/.setup-scripts/conda_env.ps1 @@ -8,8 +8,8 @@ if (($env_name -ne $null) -and ($env_name -eq $envName)) { Write-Output "Virtual Environment '$envName' already exists" return } -$DD_PIP_VERSION = '20.3.4' -$DD_SETUPTOOLS_VERSION = '44.1.1' +$DD_PIP_VERSION = '24.3.1' +$DD_SETUPTOOLS_VERSION = '75.8.2' conda create -n $envName python python=$pythonVersion -y conda activate $envName pip install --user -i https://pypi.python.org/simple pip==$DD_PIP_VERSION diff --git a/.setup-scripts/image/Dockerfile b/.setup-scripts/image/Dockerfile index 71742c04..aa9de252 100644 --- a/.setup-scripts/image/Dockerfile +++ b/.setup-scripts/image/Dockerfile @@ -2,10 +2,12 @@ # CI `docker` job passes PYTHON_BASE_IMAGE=python:3.13.14-bookworm (docker.io is logged in there). ARG PYTHON_BASE_IMAGE=registry.tooling.stackstate.io/docker/python:3.13.14-bookworm FROM ${PYTHON_BASE_IMAGE} +ARG PIP_VERSION=24.3.1 +ARG SETUPTOOLS_VERSION=75.8.2 RUN apt-get update && \ apt-get install -y apt-transport-https ca-certificates curl gnupg2 lsb-release && \ apt-get clean && \ - pip3 install -U pip setuptools codecov wheel + pip3 install "pip==${PIP_VERSION}" "setuptools==${SETUPTOOLS_VERSION}" virtualenv codecov wheel RUN install -m 0755 -d /etc/apt/keyrings && \ curl -fsSL https://download.docker.com/linux/debian/gpg -o /etc/apt/keyrings/docker.asc && \ diff --git a/.setup-scripts/image/Makefile b/.setup-scripts/image/Makefile index 6f48f7f3..644bcc65 100644 --- a/.setup-scripts/image/Makefile +++ b/.setup-scripts/image/Makefile @@ -3,6 +3,8 @@ PYTHON_SUFFIX := py313 IMAGE_REPO ?= stackstate/stackstate-agent-integrations-runner # CI `docker` job overrides with python:3.13.14-bookworm (docker.io login); local default is the mirror. PYTHON_BASE_IMAGE ?= registry.tooling.stackstate.io/docker/python:3.13.14-bookworm +include ../python_tool_versions.env +export #build: # docker build -t stackstate/stackstate-agent-integrations-runner:$(RUNTIMETAG) . @@ -21,6 +23,8 @@ PYTHON_BASE_IMAGE ?= registry.tooling.stackstate.io/docker/python:3.13.14-bookwo build: docker build --build-arg PYTHON_BASE_IMAGE=$(PYTHON_BASE_IMAGE) \ + --build-arg PIP_VERSION=$(PIP_VERSION) \ + --build-arg SETUPTOOLS_VERSION=$(SETUPTOOLS_VERSION) \ -t $(IMAGE_REPO):$(RUNTIMETAG)-$(PYTHON_SUFFIX) . push: diff --git a/.setup-scripts/python_tool_versions.env b/.setup-scripts/python_tool_versions.env new file mode 100644 index 00000000..f4ccde95 --- /dev/null +++ b/.setup-scripts/python_tool_versions.env @@ -0,0 +1,3 @@ +# Python 3.13-compatible tool pins shared by CI setup, runner image, and tox. +PIP_VERSION=24.3.1 +SETUPTOOLS_VERSION=75.8.2 diff --git a/.setup-scripts/setup_env.sh b/.setup-scripts/setup_env.sh index d84fa39e..05698079 100755 --- a/.setup-scripts/setup_env.sh +++ b/.setup-scripts/setup_env.sh @@ -7,6 +7,9 @@ set -x # This happens when using the ./run_gitlab_local.sh script export INTEGRATIONS_DIR_TMP=${CI_PROJECT_DIR:-"."} +SETUP_SCRIPTS_DIR="${INTEGRATIONS_DIR_TMP}/.setup-scripts" +# shellcheck source=python_tool_versions.env +source "${SETUP_SCRIPTS_DIR}/python_tool_versions.env" VENV_PATH=$INTEGRATIONS_DIR_TMP/venv @@ -14,12 +17,11 @@ if [ ! -d $VENV_PATH ]; then echo "$VENV_PATH doesn't exist, create the venv and loading deps" python3.13 -m venv $INTEGRATIONS_DIR_TMP/venv source $INTEGRATIONS_DIR_TMP/venv/bin/activate + pip install "pip==${PIP_VERSION}" "setuptools==${SETUPTOOLS_VERSION}" wheel pip install pylint==2.17.2 pip install docker==6.1.3 - pip install --upgrade pip setuptools pip install 'cython<3.0.0' pip install "pyyaml==6.0.1" --no-build-isolation - pip install --upgrade wheel source $INTEGRATIONS_DIR_TMP/.setup-scripts/load_deps.sh else echo "$VENV_PATH already exists, only activating the venv" diff --git a/agent_integration_sample/tox.ini b/agent_integration_sample/tox.ini index 82e73cc5..9b4e4ea7 100644 --- a/agent_integration_sample/tox.ini +++ b/agent_integration_sample/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/agent_v2_integration_sample/tox.ini b/agent_v2_integration_sample/tox.ini index 7464c3eb..5bfbfb94 100644 --- a/agent_v2_integration_sample/tox.ini +++ b/agent_v2_integration_sample/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/agent_v2_integration_stateful_sample/tox.ini b/agent_v2_integration_stateful_sample/tox.ini index e6ebc8f9..91583f71 100644 --- a/agent_v2_integration_stateful_sample/tox.ini +++ b/agent_v2_integration_stateful_sample/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/agent_v2_integration_transactional_sample/tox.ini b/agent_v2_integration_transactional_sample/tox.ini index 7464c3eb..5bfbfb94 100644 --- a/agent_v2_integration_transactional_sample/tox.ini +++ b/agent_v2_integration_transactional_sample/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/kubelet/tox.ini b/kubelet/tox.ini index 1da311ff..c13793de 100755 --- a/kubelet/tox.ini +++ b/kubelet/tox.ini @@ -5,7 +5,7 @@ envlist = py3 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 dd_check_style = true usedevelop = true platform = linux|darwin|win32 diff --git a/openmetrics/tox.ini b/openmetrics/tox.ini index 34da2298..2e9abb90 100644 --- a/openmetrics/tox.ini +++ b/openmetrics/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/servicenow/tox.ini b/servicenow/tox.ini index e9b568c8..e3428858 100644 --- a/servicenow/tox.ini +++ b/servicenow/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/splunk_base/tox.ini b/splunk_base/tox.ini index 2d029795..231d7401 100644 --- a/splunk_base/tox.ini +++ b/splunk_base/tox.ini @@ -6,7 +6,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/splunk_health/tox.ini b/splunk_health/tox.ini index db477176..acda99e5 100644 --- a/splunk_health/tox.ini +++ b/splunk_health/tox.ini @@ -6,7 +6,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 passenv = diff --git a/splunk_metric/tox.ini b/splunk_metric/tox.ini index ec817186..6ca2610a 100644 --- a/splunk_metric/tox.ini +++ b/splunk_metric/tox.ini @@ -12,7 +12,7 @@ markers = unit [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 passenv = diff --git a/splunk_topology/tox.ini b/splunk_topology/tox.ini index db477176..acda99e5 100644 --- a/splunk_topology/tox.ini +++ b/splunk_topology/tox.ini @@ -6,7 +6,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 passenv = diff --git a/stackstate_checks_dev/tox.ini b/stackstate_checks_dev/tox.ini index 103947d4..06fb9daa 100644 --- a/stackstate_checks_dev/tox.ini +++ b/stackstate_checks_dev/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true skip_install = true platform = linux|darwin|win32 diff --git a/static_health/tox.ini b/static_health/tox.ini index 2feace8c..20fbf39d 100644 --- a/static_health/tox.ini +++ b/static_health/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/static_topology/tox.ini b/static_topology/tox.ini index 07475eb0..0a974d62 100644 --- a/static_topology/tox.ini +++ b/static_topology/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/vsphere/tox.ini b/vsphere/tox.ini index 56fea2a5..3b0e5544 100644 --- a/vsphere/tox.ini +++ b/vsphere/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.2.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = diff --git a/zabbix/tox.ini b/zabbix/tox.ini index f40cb76e..6792cdc5 100644 --- a/zabbix/tox.ini +++ b/zabbix/tox.ini @@ -7,7 +7,7 @@ envlist = flake8 [testenv] -pip_version = pip==23.3.1 +pip_version = pip==24.3.1 usedevelop = true platform = linux|darwin|win32 deps = From 64ffb9a4f35a4db83f06f0e8a5d143bd795598b8 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 12:39:11 +0200 Subject: [PATCH 07/14] STAC-25137 Fix servicenow JSON error test on Python 3.13 Python 3.13's json decoder reports a different first error for the malformed fixture; accept known messages across Python versions. Co-authored-by: Cursor --- servicenow/tests/test_servicenow.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/servicenow/tests/test_servicenow.py b/servicenow/tests/test_servicenow.py index dd76327b..04df3764 100644 --- a/servicenow/tests/test_servicenow.py +++ b/servicenow/tests/test_servicenow.py @@ -723,12 +723,14 @@ def test_get_json_error_msg(self, mock_request_get): url='http://test.org') msg_py3 = 'Json parse error: "Expecting property name enclosed in double quotes: ' \ 'line 11 column 5 (char 232)" in response from url http://test.org' + msg_py3_13 = 'Json parse error: "Illegal trailing comma before end of object: ' \ + 'line 10 column 8 (char 226)" in response from url http://test.org' msg_py2 = 'Json parse error: "Expecting property name: ' \ 'line 11 column 5 (char 232)" in response from url http://test.org' - expected_msg = msg_py3 if PY3 else msg_py2 + expected_msgs = {msg_py2, msg_py3, msg_py3_13} with self.assertRaises(CheckException) as context: self.check._get_json(url, 10, {}, auth) - self.assertEqual(expected_msg, str(context.exception)) + self.assertIn(str(context.exception), expected_msgs) def test_process_components_encoding_errors(self): """ From afb6c54f742c3d9d326fcf4f9c90f06f24e5d167 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 13:23:12 +0200 Subject: [PATCH 08/14] STAC-25137 Remove unused PY3 import in servicenow tests Fixes flake8 F401 after Python 3.13 JSON error message update. Co-authored-by: Cursor --- servicenow/tests/test_servicenow.py | 1 - 1 file changed, 1 deletion(-) diff --git a/servicenow/tests/test_servicenow.py b/servicenow/tests/test_servicenow.py index 04df3764..58e2b320 100644 --- a/servicenow/tests/test_servicenow.py +++ b/servicenow/tests/test_servicenow.py @@ -13,7 +13,6 @@ import mock import pytest import requests -from six import PY3 from stackstate_checks.base import AgentIntegrationTestUtil, AgentCheck, TopologyInstance from stackstate_checks.base.errors import CheckException From 06b3a1ea94a62cdd1e35528c6d4c01dc3e9a7575 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 13:53:48 +0200 Subject: [PATCH 09/14] STAC-25137 Build new docker image. Rebuild runner with pinned pip/setuptools/virtualenv; fix PyPI publish .pypirc URL; add manual windows_smoke job; enable publish on STAC branches. Co-authored-by: Cursor --- .gitlab-ci.yml | 37 ++++++++++++++++++++- .setup-scripts/conda_env.ps1 | 23 +++++++++---- .setup-scripts/setup_artifact_publishing.sh | 2 +- 3 files changed, 54 insertions(+), 8 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 28989612..07b715fb 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -418,4 +418,39 @@ publish-checks-dev: - export VERSION=`./.setup-scripts/version.sh` - echo "__version__ = \"$VERSION\"" > stackstate_checks_dev/stackstate_checks/dev/__about__.py - cd stackstate_checks_dev && python setup.py sdist bdist_wheel upload -r gitlab - <<: *manual_job_rules + rules: + - if: '$CI_COMMIT_BRANCH =~ /^STAC-/' + when: manual + allow_failure: true + - <<: *pull_requests + when: manual + allow_failure: true + - <<: *master_branch + when: manual + allow_failure: true + - <<: *release_branch + when: manual + allow_failure: true + +windows_smoke: + <<: *windows_env + stage: test + interruptible: true + script: + - python --version + - pip --version + - pip show pip setuptools + - checksdev test ${CHECK} + rules: + - if: '$CI_COMMIT_BRANCH =~ /^STAC-/' + when: manual + allow_failure: true + - <<: *pull_requests + when: manual + allow_failure: true + - <<: *master_branch + when: manual + allow_failure: true + - <<: *release_branch + when: manual + allow_failure: true diff --git a/.setup-scripts/conda_env.ps1 b/.setup-scripts/conda_env.ps1 index 6755a21f..33028b1b 100644 --- a/.setup-scripts/conda_env.ps1 +++ b/.setup-scripts/conda_env.ps1 @@ -3,14 +3,25 @@ $pythonVersion = $args[1] if ($pythonVersion -eq '3') { $pythonVersion = '3.13.14' } -$env_name = conda env list | grep $envName | awk '{print $1}' -if (($env_name -ne $null) -and ($env_name -eq $envName)) { + +$versionsFile = Join-Path $PSScriptRoot 'python_tool_versions.env' +if (Test-Path $versionsFile) { + Get-Content $versionsFile | ForEach-Object { + if ($_ -match '^\s*([A-Z_]+)\s*=\s*(.+?)\s*$') { + Set-Variable -Name $matches[1] -Value $matches[2] -Scope Script + } + } +} +if (-not $PIP_VERSION) { $PIP_VERSION = '24.3.1' } +if (-not $SETUPTOOLS_VERSION) { $SETUPTOOLS_VERSION = '75.8.2' } + +$envExists = conda env list | Select-String -Pattern "^\s*$([regex]::Escape($envName))\s" +if ($envExists) { Write-Output "Virtual Environment '$envName' already exists" return } -$DD_PIP_VERSION = '24.3.1' -$DD_SETUPTOOLS_VERSION = '75.8.2' + conda create -n $envName python python=$pythonVersion -y conda activate $envName -pip install --user -i https://pypi.python.org/simple pip==$DD_PIP_VERSION -pip install --ignore-installed setuptools==$DD_SETUPTOOLS_VERSION +pip install --user -i https://pypi.python.org/simple "pip==$PIP_VERSION" +pip install --ignore-installed "setuptools==$SETUPTOOLS_VERSION" diff --git a/.setup-scripts/setup_artifact_publishing.sh b/.setup-scripts/setup_artifact_publishing.sh index 93052699..ec5f9f7e 100755 --- a/.setup-scripts/setup_artifact_publishing.sh +++ b/.setup-scripts/setup_artifact_publishing.sh @@ -22,7 +22,7 @@ index-servers = gitlab [gitlab] -repository = https://GITLAB_PACKAGE_REGISTRY_PYPI_URL +repository = https://${GITLAB_PACKAGE_REGISTRY_PYPI_URL} username = $GITLAB_PACKAGE_REGISTRY_USER password = GITLAB_PACKAGE_REGISTRY_PASSWORD EOF From 9602092613382a336afc1113be81a6e84dcf2941 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 13:56:34 +0200 Subject: [PATCH 10/14] STAC-25137 Fix windows_smoke check name for PowerShell CI Co-authored-by: Cursor --- .gitlab-ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 07b715fb..888bacc8 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -440,7 +440,7 @@ windows_smoke: - python --version - pip --version - pip show pip setuptools - - checksdev test ${CHECK} + - checksdev test agent_integration_sample rules: - if: '$CI_COMMIT_BRANCH =~ /^STAC-/' when: manual From 332b93d8aa48275756f3ddc936e1ba4aba130072 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 14:15:20 +0200 Subject: [PATCH 11/14] STAC-25137 Fix checks-dev publish for setuptools 75 / pip 24 Use twine upload instead of deprecated setup.py upload; run publish in the linux_deps venv with explicit linux_deps artifact dependency. Co-authored-by: Cursor --- .gitlab-ci.yml | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 888bacc8..18cda410 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -410,14 +410,20 @@ test_static_health: DOCKER_DRIVER: overlay2 publish-checks-dev: + <<: *linux_env stage: publish interruptible: true + needs: + - job: linux_deps + artifacts: true script: - .setup-scripts/setup_artifact_registry.sh - .setup-scripts/setup_artifact_publishing.sh - export VERSION=`./.setup-scripts/version.sh` - echo "__version__ = \"$VERSION\"" > stackstate_checks_dev/stackstate_checks/dev/__about__.py - - cd stackstate_checks_dev && python setup.py sdist bdist_wheel upload -r gitlab + - pip install twine + - cd stackstate_checks_dev && python setup.py sdist bdist_wheel + - cd stackstate_checks_dev && twine upload --repository gitlab dist/* rules: - if: '$CI_COMMIT_BRANCH =~ /^STAC-/' when: manual From 09d11d1b70e0a8fb28f8942d18cdf1ef67a073a4 Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 14:25:58 +0200 Subject: [PATCH 12/14] STAC-25137 Fix publish twine step working directory Co-authored-by: Cursor --- .gitlab-ci.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 18cda410..82cba32e 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -422,8 +422,7 @@ publish-checks-dev: - export VERSION=`./.setup-scripts/version.sh` - echo "__version__ = \"$VERSION\"" > stackstate_checks_dev/stackstate_checks/dev/__about__.py - pip install twine - - cd stackstate_checks_dev && python setup.py sdist bdist_wheel - - cd stackstate_checks_dev && twine upload --repository gitlab dist/* + - cd stackstate_checks_dev && python setup.py sdist bdist_wheel && twine upload --repository gitlab dist/* rules: - if: '$CI_COMMIT_BRANCH =~ /^STAC-/' when: manual From 6a646f630784a71cc0bae2894a608dd590d369ce Mon Sep 17 00:00:00 2001 From: Louis Parkin Date: Thu, 25 Jun 2026 14:28:35 +0200 Subject: [PATCH 13/14] STAC-25137 Normalize GitLab PyPI publish URL in .pypirc Avoid double https:// when CI already supplies a full repository URL. Co-authored-by: Cursor --- .setup-scripts/setup_artifact_publishing.sh | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.setup-scripts/setup_artifact_publishing.sh b/.setup-scripts/setup_artifact_publishing.sh index ec5f9f7e..34c54255 100755 --- a/.setup-scripts/setup_artifact_publishing.sh +++ b/.setup-scripts/setup_artifact_publishing.sh @@ -13,7 +13,12 @@ if [ -n "$missing" ]; then fi echo "→ Configuring .pypirc for publishing to GitLab Package Registry..." -echo "GitLab PyPI URL: $GITLAB_PACKAGE_REGISTRY_PYPI_URL" + +PYPI_REPOSITORY_URL="${GITLAB_PACKAGE_REGISTRY_PYPI_URL}" +if [[ "${PYPI_REPOSITORY_URL}" != http://* && "${PYPI_REPOSITORY_URL}" != https://* ]]; then + PYPI_REPOSITORY_URL="https://${PYPI_REPOSITORY_URL}" +fi +echo "GitLab PyPI URL: ${PYPI_REPOSITORY_URL}" # setup .pypirc cat > ~/.pypirc < Date: Thu, 25 Jun 2026 14:35:36 +0200 Subject: [PATCH 14/14] STAC-25137 Remove windows_smoke CI job Windows is no longer built or supported. Co-authored-by: Cursor --- .gitlab-ci.yml | 23 ----------------------- 1 file changed, 23 deletions(-) diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 82cba32e..a8089cef 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -436,26 +436,3 @@ publish-checks-dev: - <<: *release_branch when: manual allow_failure: true - -windows_smoke: - <<: *windows_env - stage: test - interruptible: true - script: - - python --version - - pip --version - - pip show pip setuptools - - checksdev test agent_integration_sample - rules: - - if: '$CI_COMMIT_BRANCH =~ /^STAC-/' - when: manual - allow_failure: true - - <<: *pull_requests - when: manual - allow_failure: true - - <<: *master_branch - when: manual - allow_failure: true - - <<: *release_branch - when: manual - allow_failure: true