@@ -144,7 +144,7 @@ build:
144144 script :
145145 - |
146146 set -euo pipefail
147- version="$ (python3 -c 'import tomllib; print( tomllib.load(open("pyproject.toml", "rb"))["project"][" version"])')"
147+ read -r package version < < (python3 -c 'import tomllib; p = tomllib.load(open("pyproject.toml", "rb"))["project"]; print(p["name"], p[" version"])')
148148 if [ -n "${CI_COMMIT_TAG:-}" ] && [ "v${version}" != "${CI_COMMIT_TAG}" ]; then
149149 echo "tag ${CI_COMMIT_TAG} does not match pyproject.toml version ${version}"
150150 exit 1
@@ -156,7 +156,7 @@ build:
156156 /tmp/smoke/bin/ldo --version
157157 /tmp/smoke/bin/ldo --help > /dev/null
158158 # For the jobs after this one: the version, and the tags each image is published with.
159- echo "VERSION= ${version}" > build.env
159+ printf 'PACKAGE=%s\nVERSION=%s\n' "${package}" " ${version}" > build.env
160160 mkdir -p image-tags
161161 for variant in az tool; do
162162 python3 scripts/image_tags.py --version "${version}" --variant "${variant}" \
@@ -248,8 +248,7 @@ container:
248248
249249# Publish (release tags only) ---------------------------------------------------------
250250
251- # After the images, so the package never exists without them. A file already there (a
252- # retried pipeline) is skipped, not an error.
251+ # After the images, so the package never exists without them.
253252package :
254253 stage : publish
255254 needs : [build, container]
@@ -258,10 +257,44 @@ package:
258257 - *release-tag
259258 variables :
260259 UV_PUBLISH_URL : ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi
261- UV_PUBLISH_CHECK_URL : ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/pypi/simple
262260 UV_PUBLISH_USERNAME : gitlab-ci-token
263261 script :
264- - UV_PUBLISH_PASSWORD="${CI_JOB_TOKEN}" uv publish dist/*
262+ - |
263+ set -euo pipefail
264+ # Whether this version is here already (a retried pipeline), asked of the packages
265+ # API. Not of the PyPI index (uv publish --check-url): for a package it does not hold,
266+ # GitLab redirects there to pypi.org, whose files would pass for its own.
267+ present="$(python3 - <<'PY'
268+ import json
269+ import os
270+ import urllib.parse
271+ import urllib.request
272+
273+ env = os.environ
274+ query = urllib.parse.urlencode(
275+ {"package_type": "pypi", "package_name": env["PACKAGE"], "package_version": env["VERSION"]}
276+ )
277+ request = urllib.request.Request(
278+ f"{env['CI_API_V4_URL']}/projects/{env['CI_PROJECT_ID']}/packages?{query}",
279+ headers={"JOB-TOKEN": env["CI_JOB_TOKEN"]},
280+ )
281+ with urllib.request.urlopen(request, timeout=30) as response:
282+ packages = json.load(response)
283+
284+ def normal(name):
285+ return name.casefold().replace("_", "-").replace(".", "-")
286+
287+ print(any(
288+ normal(item["name"]) == normal(env["PACKAGE"]) and item["version"] == env["VERSION"]
289+ for item in packages
290+ ))
291+ PY
292+ )"
293+ if [ "${present}" = True ]; then
294+ echo "${PACKAGE} ${VERSION} is in the package registry already"
295+ exit 0
296+ fi
297+ UV_PUBLISH_PASSWORD="${CI_JOB_TOKEN}" uv publish dist/*.whl dist/*.tar.gz
265298
266299# The GitLab release, last: how to install from this project's registries, and the files'
267300# checksums. A release that is there already (a retried pipeline) is left as it is.
@@ -283,8 +316,9 @@ release:
283316 import urllib.request
284317
285318 env = os.environ
286- tag, version = env["CI_COMMIT_TAG"], env["VERSION"]
287- files = sorted(pathlib.Path("dist").iterdir())
319+ tag, package, version = env["CI_COMMIT_TAG"], env["PACKAGE"], env["VERSION"]
320+ dist = pathlib.Path("dist")
321+ files = sorted([*dist.glob("*.whl"), *dist.glob("*.tar.gz")])
288322 sums = "\n".join(f"{hashlib.sha256(f.read_bytes()).hexdigest()} {f.name}" for f in files)
289323 index = f"{env['CI_API_V4_URL']}/projects/{env['CI_PROJECT_ID']}/packages/pypi/simple"
290324 image = env["CI_REGISTRY_IMAGE"]
@@ -293,7 +327,7 @@ release:
293327 "" if final else "A pre-release: installed only by asking for this version.\n",
294328 f"What changed: [CHANGELOG.md]({env['CI_PROJECT_URL']}/-/blob/{tag}/CHANGELOG.md).\n",
295329 "```bash",
296- f"uv tool install --index {index} libre-devops-helpers =={version}",
330+ f"uv tool install --index {index} {package} =={version}",
297331 f"podman pull {image}:{version} # with the Azure CLI",
298332 f"podman pull {image}:{version}-slim # the tool alone",
299333 "```\n",
0 commit comments